Compare commits
6 Commits
4cfaa2dc77
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8d92d1b01 | ||
|
|
ddbfd03e75 | ||
|
d1c7f09015
|
|||
|
d2f8f995f0
|
|||
|
5ef9a397ca
|
|||
|
325ab1f45e
|
@@ -1,3 +1,34 @@
|
||||
## v0.2.0 (2026-02-14)
|
||||
|
||||
### Feat
|
||||
|
||||
- Simplified sisyphus prompt to improve functionality
|
||||
- Supported the injection of RAG sources into the prompt, not just via the `.sources rag` command in the REPL so models can directly reference the documents that supported their responses
|
||||
- Created the Sisyphus agent to make Loki function like Claude Code, Gemini, Codex, etc.
|
||||
- Created the Oracle agent to handle high-level architectural decisions and design questions about a given codebase
|
||||
- Updated the coder agent to be much more task-focused and to be delegated to by Sisyphus
|
||||
- Created the explore agent for exploring codebases to help answer questions
|
||||
- Use the official atlassian MCP server for the jira-helper agent
|
||||
- Created fs_glob to enable more targeted file exploration utilities
|
||||
- Created a new tool 'fs_grep' to search a given file's contents for relevant lines to reduce token usage for smaller models
|
||||
- Created the new fs_read tool to enable controlled reading of a file
|
||||
- Let agent level variables be defined to bypass guard protections for tool invocations
|
||||
- Implemented a built-in task management system to help smaller LLMs complete larger multistep tasks and minimize context drift
|
||||
- Improved tool and MCP invocation error handling by returning stderr to the model when it is available
|
||||
- Added variable interpolation for conversation starters in agents
|
||||
- Implemented retry logic for failed tool invocations so the LLM can learn from the result and try again; Also implemented chain loop detection to prevent loops
|
||||
- Added gemini-3-pro to the supported vertexai models
|
||||
- Added an environment variable that lets users bypass guard operations in bash scripts. This is useful for agent routing
|
||||
- Added support for thought-signatures for Gemini 3+ models
|
||||
|
||||
### Fix
|
||||
|
||||
- Improved continuation prompt to not make broad todo-items
|
||||
- Allow auto-continuation to work in agents after a session is compressed and if there's still unfinish items in the to-do list
|
||||
- fs_ls and fs_cat outputs should always redirect to "$LLM_OUTPUT" including on errors.
|
||||
- Claude tool calls work incorrectly when tool doesn't require any arguments or flags; would provide an empty JSON object or error on no args
|
||||
- Fixed a bug where --agent-variable values were not being passed to the agents
|
||||
|
||||
## v0.1.3 (2025-12-13)
|
||||
|
||||
### Feat
|
||||
|
||||
Generated
+600
-456
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "loki-ai"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
edition = "2024"
|
||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||
description = "An all-in-one, batteries included LLM CLI Tool"
|
||||
|
||||
@@ -116,68 +116,23 @@ instructions: |
|
||||
|
||||
User: "Add a new API endpoint for user profiles"
|
||||
|
||||
```
|
||||
1. start_task --goal "Add user profiles API endpoint"
|
||||
2. todo__init --goal "Add user profiles API endpoint"
|
||||
3. todo__add --task "Explore existing API patterns and code conventions"
|
||||
4. todo__add --task "Implement profile endpoint"
|
||||
5. todo__add --task "Verify implementation with build/test"
|
||||
6. todo__add --task "Write/update tests for new/updated code (if necessary)"
|
||||
7. todo__add --task "Verify tests pass"
|
||||
8. todo__add --task "Clean-up code and clear any linter warnings"
|
||||
9. todo__add --task "Verify clean-up with build/test"
|
||||
10. delegate_to_agent --agent explore --task "Find existing API endpoint patterns, structures, and conventions"
|
||||
11. todo__done --id 1
|
||||
11. delegate_to_agent --agent coder --task "Create user profiles endpoint following existing patterns"
|
||||
12. todo__done --id 2
|
||||
13. run_build
|
||||
14. run_tests
|
||||
15. todo__done --id 3
|
||||
16. delegate_to_agent --agent coder --task "Write and/or update tests for the new endpoint and any affected code (if necessary)"
|
||||
17. todo__done --id 4
|
||||
18. run_tests
|
||||
19. todo__done --id 5
|
||||
20. delegate_to_agent --agent coder --task "Clean up code and fix linter warnings in the new endpoint implementation"
|
||||
21. todo__done --id 6
|
||||
22. run_build
|
||||
23. run_tests
|
||||
24. todo__done --id 7
|
||||
25. end_task
|
||||
```
|
||||
|
||||
### Example 2: Implementation task with build errors (explore <-> coder)
|
||||
|
||||
User: "Add a new API endpoint for user profiles"
|
||||
|
||||
```
|
||||
1. start_task --goal "Add user profiles API endpoint"
|
||||
2. todo__init --goal "Add user profiles API endpoint"
|
||||
3. todo__add --task "Explore existing API patterns"
|
||||
4. todo__add --task "Implement profile endpoint"
|
||||
5. todo__add --task "Verify implementation with build/test"
|
||||
6. todo__add --task "Clean-up code and clear any linter warnings"
|
||||
7. todo__add --task "Verify clean-up with build/test"
|
||||
8. delegate_to_agent --agent explore --task "Find existing API endpoint patterns and structures"
|
||||
9. todo__done --id 1
|
||||
10. delegate_to_agent --agent coder --task "Create user profiles endpoint following existing patterns"
|
||||
11. todo__done --id 2
|
||||
12. run_build
|
||||
13. todo__add --task "Fix compilation errors"
|
||||
14. todo__add --task "Verify fixes with build/test"
|
||||
15. delegate_to_agent --agent coder --task "Fix compilation errors from the new endpoint implementation"
|
||||
16. todo__done --id 5
|
||||
17. run_build
|
||||
18. run_tests
|
||||
19. todo__done --id 6
|
||||
20. todo__done --id 3
|
||||
21. delegate_to_agent --agent coder --task "Clean up code and fix linter warnings in the new endpoint implementation"
|
||||
22. todo__done --id 4
|
||||
23. run_build
|
||||
24. run_tests
|
||||
25. todo__done --id 7
|
||||
5. todo__add --task "Verify with build/test"
|
||||
6. delegate_to_agent --agent explore --task "Find existing API endpoint patterns and structures"
|
||||
7. todo__done --id 1
|
||||
8. delegate_to_agent --agent coder --task "Create user profiles endpoint following existing patterns"
|
||||
9. todo__done --id 2
|
||||
10. run_build
|
||||
11. run_tests
|
||||
12. todo__done --id 3
|
||||
13. end_task
|
||||
```
|
||||
|
||||
### Example 3: Architecture/design question (explore -> oracle)
|
||||
### Example 2: Architecture/design question (explore -> oracle)
|
||||
|
||||
User: "How should I structure the authentication for this app?"
|
||||
|
||||
@@ -193,7 +148,7 @@ instructions: |
|
||||
9. end_task
|
||||
```
|
||||
|
||||
### Example 4: Vague/open-ended question (oracle directly)
|
||||
### Example 3: Vague/open-ended question (oracle directly)
|
||||
|
||||
User: "What do you think of this codebase structure?"
|
||||
|
||||
|
||||
+10
-2
@@ -41,7 +41,7 @@ vault_password_file: null # Path to a file containing the password for th
|
||||
# See the [Tools documentation](./docs/function-calling/TOOLS.md) for more details
|
||||
function_calling: true # Enables or disables function calling (Globally).
|
||||
mapping_tools: # Alias for a tool or toolset
|
||||
fs: 'fs_cat,fs_ls,fs_mkdir,fs_rm,fs_write'
|
||||
fs: 'fs_cat,fs_ls,fs_mkdir,fs_rm,fs_write,fs_read,fs_glob,fs_grep'
|
||||
enabled_tools: null # Which tools to enable by default. (e.g. 'fs,web_search_loki')
|
||||
visible_tools: # Which tools are visible to be compiled (and are thus able to be defined in 'enabled_tools')
|
||||
# - demo_py.py
|
||||
@@ -53,6 +53,9 @@ visible_tools: # Which tools are visible to be compiled (and a
|
||||
# - fetch_url_via_jina.sh
|
||||
- fs_cat.sh
|
||||
- fs_ls.sh
|
||||
# - fs_read.sh
|
||||
# - fs_glob.sh
|
||||
# - fs_grep.sh
|
||||
# - fs_mkdir.sh
|
||||
# - fs_patch.sh
|
||||
# - fs_write.sh
|
||||
@@ -92,7 +95,7 @@ rag_reranker_model: null # Specifies the reranker model used for sorting
|
||||
rag_top_k: 5 # Specifies the number of documents to retrieve for answering queries
|
||||
rag_chunk_size: null # Defines the size of chunks for document processing in characters
|
||||
rag_chunk_overlap: null # Defines the overlap between chunks
|
||||
# Defines the query structure using variables like __CONTEXT__ and __INPUT__ to tailor searches to specific needs
|
||||
# Defines the query structure using variables like __CONTEXT__, __SOURCES__, and __INPUT__ to tailor searches to specific needs
|
||||
rag_template: |
|
||||
Answer the query based on the context while respecting the rules. (user query, some textual context and rules, all inside xml tags)
|
||||
|
||||
@@ -100,6 +103,10 @@ rag_template: |
|
||||
__CONTEXT__
|
||||
</context>
|
||||
|
||||
<sources>
|
||||
__SOURCES__
|
||||
</sources>
|
||||
|
||||
<rules>
|
||||
- If you don't know, just say so.
|
||||
- If you are not sure, ask for clarification.
|
||||
@@ -107,6 +114,7 @@ rag_template: |
|
||||
- If the context appears unreadable or of poor quality, tell the user then answer as best as you can.
|
||||
- If the answer is not in the context but you think you know the answer, explain that to the user then answer with your own knowledge.
|
||||
- Answer directly and without using xml tags.
|
||||
- When using information from the context, cite the relevant source from the <sources> section.
|
||||
</rules>
|
||||
|
||||
<user_query>
|
||||
|
||||
+11
-3
@@ -265,12 +265,14 @@ When you use RAG in Loki, after Loki performs the lookup for relevant chunks of
|
||||
will add the retrieved text chunks as context to your query before sending it to the model. The format of this context
|
||||
is determined by the `rag_template` setting in your global Loki configuration file.
|
||||
|
||||
This template utilizes two placeholders:
|
||||
This template utilizes three placeholders:
|
||||
* `__INPUT__`: The user's actual query
|
||||
* `__CONTEXT__`: The context retrieved from RAG
|
||||
* `__SOURCES__`: A numbered list of the source file paths or URLs that the retrieved context came from
|
||||
|
||||
These placeholders are replaced with the corresponding values into the template and make up what's actually passed to
|
||||
the model at query-time.
|
||||
the model at query-time. The `__SOURCES__` placeholder enables the model to cite which documents its answer is based on,
|
||||
which is especially useful when building knowledge-base assistants that need to provide verifiable references.
|
||||
|
||||
The default template that Loki uses is the following:
|
||||
|
||||
@@ -281,6 +283,10 @@ Answer the query based on the context while respecting the rules. (user query, s
|
||||
__CONTEXT__
|
||||
</context>
|
||||
|
||||
<sources>
|
||||
__SOURCES__
|
||||
</sources>
|
||||
|
||||
<rules>
|
||||
- If you don't know, just say so.
|
||||
- If you are not sure, ask for clarification.
|
||||
@@ -288,6 +294,7 @@ __CONTEXT__
|
||||
- If the context appears unreadable or of poor quality, tell the user then answer as best as you can.
|
||||
- If the answer is not in the context but you think you know the answer, explain that to the user then answer with your own knowledge.
|
||||
- Answer directly and without using xml tags.
|
||||
- When using information from the context, cite the relevant source from the <sources> section.
|
||||
</rules>
|
||||
|
||||
<user_query>
|
||||
@@ -296,4 +303,5 @@ __INPUT__
|
||||
```
|
||||
|
||||
You can customize this template by specifying the `rag_template` setting in your global Loki configuration file. Your
|
||||
template *must* include both the `__INPUT__` and `__CONTEXT__` placeholders in order for it to be valid.
|
||||
template *must* include both the `__INPUT__` and `__CONTEXT__` placeholders in order for it to be valid. The
|
||||
`__SOURCES__` placeholder is optional. If it is omitted, source references will not be included in the prompt.
|
||||
|
||||
@@ -38,6 +38,9 @@ be enabled/disabled can be found in the [Configuration](#configuration) section
|
||||
| [`fetch_url_via_curl.sh`](../../assets/functions/tools/fetch_url_via_curl.sh) | Extract the content from a given URL using cURL. | 🔴 |
|
||||
| [`fetch_url_via_jina.sh`](../../assets/functions/tools/fetch_url_via_jina.sh) | Extract the content from a given URL using Jina. | 🔴 |
|
||||
| [`fs_cat.sh`](../../assets/functions/tools/fs_cat.sh) | Read the contents of a file at the specified path. | 🟢 |
|
||||
| [`fs_read.sh`](../../assets/functions/tools/fs_read.sh) | Controlled reading of the contents of a file at the specified path with line numbers, offset, and limit to read specific sections. | 🟢 |
|
||||
| [`fs_glob.sh`](../../assets/functions/tools/fs_glob.sh) | Find files by glob pattern. Returns matching file paths sorted by modification time. | 🟢 |
|
||||
| [`fs_grep.sh`](../../assets/functions/tools/fs_grep.sh) | Search file contents using regular expressions. Returns matching file paths and lines. | 🟢 |
|
||||
| [`fs_ls.sh`](../../assets/functions/tools/fs_ls.sh) | List all files and directories at the specified path. | 🟢 |
|
||||
| [`fs_mkdir.sh`](../../assets/functions/tools/fs_mkdir.sh) | Create a new directory at the specified path. | 🔴 |
|
||||
| [`fs_patch.sh`](../../assets/functions/tools/fs_patch.sh) | Apply a patch to a file at the specified path. <br>This can be used to edit a file without having to rewrite the whole file. | 🔴 |
|
||||
|
||||
+9
-3
@@ -96,6 +96,10 @@ const RAG_TEMPLATE: &str = r#"Answer the query based on the context while respec
|
||||
__CONTEXT__
|
||||
</context>
|
||||
|
||||
<sources>
|
||||
__SOURCES__
|
||||
</sources>
|
||||
|
||||
<rules>
|
||||
- If you don't know, just say so.
|
||||
- If you are not sure, ask for clarification.
|
||||
@@ -103,6 +107,7 @@ __CONTEXT__
|
||||
- If the context appears unreadable or of poor quality, tell the user then answer as best as you can.
|
||||
- If the answer is not in the context but you think you know the answer, explain that to the user then answer with your own knowledge.
|
||||
- Answer directly and without using xml tags.
|
||||
- When using information from the context, cite the relevant source from the <sources> section.
|
||||
</rules>
|
||||
|
||||
<user_query>
|
||||
@@ -1756,10 +1761,10 @@ impl Config {
|
||||
abort_signal: AbortSignal,
|
||||
) -> Result<String> {
|
||||
let (reranker_model, top_k) = rag.get_config();
|
||||
let (embeddings, ids) = rag
|
||||
let (embeddings, sources, ids) = rag
|
||||
.search(text, top_k, reranker_model.as_deref(), abort_signal)
|
||||
.await?;
|
||||
let text = config.read().rag_template(&embeddings, text);
|
||||
let text = config.read().rag_template(&embeddings, &sources, text);
|
||||
rag.set_last_sources(&ids);
|
||||
Ok(text)
|
||||
}
|
||||
@@ -1781,7 +1786,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rag_template(&self, embeddings: &str, text: &str) -> String {
|
||||
pub fn rag_template(&self, embeddings: &str, sources: &str, text: &str) -> String {
|
||||
if embeddings.is_empty() {
|
||||
return text.to_string();
|
||||
}
|
||||
@@ -1789,6 +1794,7 @@ impl Config {
|
||||
.as_deref()
|
||||
.unwrap_or(RAG_TEMPLATE)
|
||||
.replace("__CONTEXT__", embeddings)
|
||||
.replace("__SOURCES__", sources)
|
||||
.replace("__INPUT__", text)
|
||||
}
|
||||
|
||||
|
||||
+36
-4
@@ -298,16 +298,48 @@ impl Rag {
|
||||
top_k: usize,
|
||||
rerank_model: Option<&str>,
|
||||
abort_signal: AbortSignal,
|
||||
) -> Result<(String, Vec<DocumentId>)> {
|
||||
) -> Result<(String, String, Vec<DocumentId>)> {
|
||||
let ret = abortable_run_with_spinner(
|
||||
self.hybird_search(text, top_k, rerank_model),
|
||||
"Searching",
|
||||
abort_signal,
|
||||
)
|
||||
.await;
|
||||
let (ids, documents): (Vec<_>, Vec<_>) = ret?.into_iter().unzip();
|
||||
let embeddings = documents.join("\n\n");
|
||||
Ok((embeddings, ids))
|
||||
let results = ret?;
|
||||
let ids: Vec<_> = results.iter().map(|(id, _)| *id).collect();
|
||||
let embeddings = results
|
||||
.iter()
|
||||
.map(|(id, content)| {
|
||||
let source = self.resolve_source(id);
|
||||
format!("[Source: {source}]\n{content}")
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n");
|
||||
let sources = self.format_sources(&ids);
|
||||
Ok((embeddings, sources, ids))
|
||||
}
|
||||
|
||||
fn resolve_source(&self, id: &DocumentId) -> String {
|
||||
let (file_index, _) = id.split();
|
||||
self.data
|
||||
.files
|
||||
.get(&file_index)
|
||||
.map(|f| f.path.clone())
|
||||
.unwrap_or_else(|| "unknown".to_string())
|
||||
}
|
||||
|
||||
fn format_sources(&self, ids: &[DocumentId]) -> String {
|
||||
let mut seen = IndexSet::new();
|
||||
for id in ids {
|
||||
let (file_index, _) = id.split();
|
||||
if let Some(file) = self.data.files.get(&file_index) {
|
||||
seen.insert(file.path.clone());
|
||||
}
|
||||
}
|
||||
seen.into_iter()
|
||||
.map(|path| format!("- {path}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
pub async fn sync_documents(
|
||||
|
||||
Reference in New Issue
Block a user