6 Commits

Author SHA1 Message Date
github-actions[bot]
e8d92d1b01 chore: bump Cargo.toml to 0.2.0
CI / All (macos-latest) (push) Has been cancelled
CI / All (ubuntu-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
2026-02-14 01:41:41 +00:00
github-actions[bot]
ddbfd03e75 bump: version 0.1.3 → 0.2.0 [skip ci] 2026-02-14 01:41:29 +00:00
d1c7f09015 feat: Simplified sisyphus prompt to improve functionality
CI / All (macos-latest) (push) Has been cancelled
CI / All (ubuntu-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
2026-02-13 18:36:10 -07:00
d2f8f995f0 feat: 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
CI / All (macos-latest) (push) Has been cancelled
CI / All (ubuntu-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
2026-02-13 17:45:56 -07:00
5ef9a397ca docs: updated the tools documentation to mention the new fs_read, fs_grep, and fs_glob tools
CI / All (macos-latest) (push) Has been cancelled
CI / All (ubuntu-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
2026-02-13 16:53:00 -07:00
325ab1f45e docs: updated the default configuration example to have the new fs_read, fs_glob, fs_grep global functions
CI / All (macos-latest) (push) Has been cancelled
CI / All (ubuntu-latest) (push) Has been cancelled
CI / All (windows-latest) (push) Has been cancelled
2026-02-13 16:23:49 -07:00
9 changed files with 712 additions and 525 deletions
+31
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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"
+11 -56
View File
@@ -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
View File
@@ -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
View File
@@ -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.
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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(