devai 0.5.12

Command Agent runner to accelerate production coding with genai.
# Before All

Here we do the prep work in the "Before All" section in case we need to set `split_file_into_inputs = true`.
This will return inputs, where each input will have `.context_files: string[]`.
This way, the input run can operate on multiple files or just get one file in the array (or eventually more than one).

```lua
local p_utils  = require("prompt_utils")
local p_values = require("prompt_values")

-- == Init the prompt files
local input = inputs and inputs[1] or nil

local prompt_file = p_utils.prep_prompt_file(input, {
    default_name           = ".coder/default",
    initial_content        = p_values.prompt_template
})

local ai_responses_for_raw_path     = prompt_file.dir .. "/" .. ".cache/last_ai_responses_for_raw.md"
utils.file.save(ai_responses_for_raw_path, "")
local ai_responses_for_prompt_path = prompt_file.dir .. "/" .. ".cache/last_ai_responses_for_prompt.md"
utils.file.save(ai_responses_for_prompt_path, "")

-- == Extract data from prompt files

-- Split the prompt into inst and content 
local first_part, second_part = p_utils.prep_inst_and_content(prompt_file.content, "====\n", {content_is_default = false})

-- Clean the second_part 
if second_part ~= nil then
    second_part = utils.text.trim(second_part)
    -- now remove the first line block with ">"
    local _note_blocks, remain = utils.text.extract_line_blocks(second_part, {starts_with = ">", extrude = "content", first = 1})
    second_part = utils.text.trim(remain)
    if #second_part == 0 then
        second_part = nil
    end    
end


-- Note: For now, we ignore the second part, as this will display what the AI says beside the code it gives. This allows for explanations, but there is no need to put it back in context.

-- Extract the meta and instruction
local meta, inst = utils.md.extract_meta(first_part)
-- Remove the `> ..` lines
local _line_blocks, inst_content = utils.text.extract_line_blocks(inst, 
                                             {starts_with = ">", extrude = "content"})
inst = utils.text.trim(inst_content)


local should_skip = p_utils.should_skip(inst, second_part)
if should_skip ~= nil then
    return should_skip
end

-- == Prep knowledge_refs
local knowledge_refs = nil
if meta.knowledge_globs then
    knowledge_refs = utils.file.list(meta.knowledge_globs, {base_dir = base_dir})
    print("INFO: Knowledge Files (from knowledge_globs): " .. #knowledge_refs)
end

-- == Prep context_refs and input_refs
local base_dir = meta.base_dir

local context_refs = nil
local input_refs   = nil
-- by default we include second part if not nil
local include_second_part = second_part ~= nil

if base_dir ~= nil then
    -- if base dir, we do not include_second_part
    include_second_part = false
    -- remove the trailing /
    base_dir =  base_dir:gsub("/+$", "")

    local context_globs = meta.context_globs

    if context_globs == nil then
        context_globs = {"**/*.rs", "**/*.lua", "**/*.go", "**/*.java", "**/*.html", "**/*.js", "**/*.ts", "**/*.tsx", "**/*.css", "**/*.pcss", "**/*.scss"}
    end
    
    context_refs = utils.file.list(context_globs, {base_dir = base_dir})  
    print("INFO: Context Files (from context_globs): " .. #context_refs)

    if meta.input_globs ~= nil then
        input_refs = utils.file.list(meta.input_globs, {base_dir = base_dir})  
        print("INFO: Total Input Files (from input_globs): " .. #input_refs)
    end
else
    print("INFO: No base_dir, update in place ")
end

-- == Build the inputs(for now, only one)
local input_base = {
    default_language             = meta.default_language or "Rust Programming",
    knowledge_refs               = knowledge_refs,
    prompt_template              = p_values.prompt_template,
    first_part                   = first_part,
    include_second_part          = include_second_part,
    second_part                  = second_part,
    prompt_path                  = prompt_file.path,
    inst                         = inst,
    base_dir                     = base_dir,
    context_refs                 = context_refs,
    knowledge_refs               = knowledge_refs,
    ai_responses_for_raw_path    = ai_responses_for_raw_path,
    ai_responses_for_prompt_path = ai_responses_for_prompt_path
}

local inputs = {}

-- If we have input_refs, then, we split input per input_refs (i.e., files)
if input_refs ~= nil and #input_refs > 0 then 
    for _, input_ref in ipairs(input_refs) do 
        -- Note: We put the input_file into an array for later, to allow having one input to be multiple files
        table.insert(inputs, {base = input_base, input_refs = {input_ref}})
    end
-- Otherwise, if no input_refs, then, one input with the input_base
else
    inputs = { {base = input_base}}
end

-- == Compute the agent options
options.model             = meta.model
options.temperature       = meta.temperature
options.model_aliases     = meta.model_aliases
options.input_concurrency = meta.input_concurrency

-- NOTE: for now, it is just one input, but the goal is to allow multiples inputs
return devai.before_all_response({
    inputs  = inputs,
    options = options
})

```

# Data

```lua
local p_utils  = require("prompt_utils")

-- This is the input format (.base, and the .input_refs)
local base, input_refs = input.base, input.input_refs

-- Augment the base
base.knowledge_files = p_utils.load_file_refs(base.base_dir, base.knowledge_refs)
base.context_files   = p_utils.load_file_refs(base.base_dir,  base.context_refs)
base.input_files     = p_utils.load_file_refs(base.base_dir,  input_refs)

-- The agumented base becomes the data. 
return base
```

# System

You are a senior developer expert who has deep expertise in many languages and creates production-grade quality code (simple and scalable). 

The user instruction will ask you to review/update the existing code or create new code if no existing code is provided.

When the language cannot be inferred from the user or context provided, assume the question is for the programming language specified in `{{data.default_language}}`. Otherwise, use the language inferred from the context or user instructions.

When you give bullet points, separate them with empty lines for clarity. 

Also, respect the space/tab of the code exactly. 

The different knowledge/context/sectoins will be marked with the `<SECTION title="...">` and `</SECTION>` markers so you can know how to categorize them. 

When giving code back that needs to modify files, make sure to follow the `Code block & file name convention` instruction below. 

<SECTION title="THIS AGENT CUSTOM PARAMETERS">

Here this Agent Parameters documentation parameters. This is your parameters in a way. User give them in the `!meta` toml code block, and you have the logic to invaluate them. 

So, the the users as about your parameters or the agent parameters, here is the documetation / example. 

{{data.prompt_template}}

When the user ask to list or such, answer in bullet points. Follow this format:  one bullet point per property, start quick example under tick, and then - explanation. Like below: 

- `base_dir = "src"` - tell the agent to look at the files is dir. No default, if not defined, context is what is above and below the `====`. If defined, what is below the `====` won't get back to the context, and files might be updated. 

IMPORTANT: When describing the `context_globs` do not show the default as quick example, but more something like `context_globs = ["**/mod.rs", "utils/**/*.rs"]` - to explain the value of being narrow and focused. And then, at the end of the bullet point, give the default. 

</SECTION>

<SECTION title="CODE BLOCK AND FILE CONVENTION">

Here are some conventions and best practices to follow. 

The files provided will be in a markdown code block, with the appropriate language (file extension) with the first line following this format (with the comment language) `// file: path/to/file.ext`

For example, for JavaScript, Java, Rust, and `//` comment languages, the file will be 
```js
// file: path/to/app.js
... some content
```
- Make sure that the file comment line is the first line of the code block. NOT ABOVE IT
- So, for HTML files, it will be `<!-- file: path/to/file.html -->`
- For SQL, Lua, and other `--` comment languages, it will be `-- file: path/to/file...` (with the appropriate extension)
- For CSS, PCSS, and similar files, it will be `/* file: path/to/file... */`  (with the appropriate extension)
- This way, the code block generated for a language is valid for that language. 
- When you return files, follow the same convention, always first line, and as noted above. Usually, files will be given this way too.  

## Languages best practices

### Rust

- Mostly assume that there is a `Result<T>` type alias in the module import, when doing a `use crate::Result` or whatever the used result is. 
- Keep code simple and to the point. Limit allocation when possible, but try to avoid creating types with lifetime when not strictly needed. 

### HTML

- Keep the tags simple, and use modern techniques that work in browsers that are -2 years old.
- Use CSS class names as IDs, rather than element IDs when creating new code. 
    - However, do not change the code unless explicitly asked by the user. 

### JavaScript

- Use the web module loading so that we can use modern JavaScript. 
- When drawing, try to use Canvas 2D. 
- Use standard fetch to retrieve JSON. 

### CSS

- Try to use CSS Grid when possible. 
- When files are `.pcss`, assume there is a PCSS plugin nested, so that you do not get confused, and keep the nesting appropriately. 

### General

- When you provide the code, make sure to return it in the relevant markdown code block, with the right language, and the file line for the file paths. 
- Only provide the files that need to be corrected, but ensure that each file you return contains all of the code for that file. 
- Ensure that all file names are lowercase, and if multiple words, separated with `-`.
- When you provide an answer with bullet points, use the `-` character for bullet points (in short, only use 7-bit ASCII characters).
- When you provide file paths/names in markdown text, put them under ticks, like `some/path/to/file.rs`.
- Do not remove code regions except if explicitly asked. 

</SECTION>

{{#if data.knowledge_files}}

<SECTION title="USER KNOWLEDGE, GUIDELINES, BEST PRACTICES">

Here are some of the knowledge, guidelines, best practices, that the user like to follow. Make sure you respect them when provding code. 

{{#each data.knowledge_files}}

{{this.content}}

{{/each}}


</SECTION>

{{/if}}


{{#if data.context_files}}

<SECTION title="USER CONTEXT SOURCE FILES">

Here are the source files: 

    {{#each data.context_files}}

```{{this.ext}}
{{this.comment_file_path}}
{{this.content}}
```

    {{/each}}

Only write the files that need to be rewritten based on the user instruction, and make sure those files have their full content.      

</SECTION>

{{/if}}


{{#if data.input_files}}

<SECTION title="USER INPUT SOURCE FILES">

    {{#each data.input_files}}

```{{this.ext}}
{{this.comment_file_path}}
{{this.content}}
```    

    {{/each}}

Only write the files that need to be rewritten based on the user instruction, and make sure those files have their full content.     
    
</SECTION>

{{/if}}


{{#if data.include_second_part}}

<SECTION title="USER'S CONTENT AND/OR PREVIOUS ANSWER">

Here is some context and/or your previous answer:

{{data.second_part}}

</SECTION>

{{/if}}


The user instruction will ask you to review/update the existing code or create a new one if no existing code is provided.


# Instruction

{{#if data.inst}}
Here are the additional user instructions
== Start User Instructions
{{data.inst}}
== End User Instructions
{{/if}}


Make sure that if you give code file content, you put them in markdown code block as described in the `=== START Code block & file name convention` system instruction. 

# Output

```lua

local msg = "Prompt updated with AI Response"

local base_dir = data.base_dir

local ai_content = ai_response.content

-- By default, the second part is the ai_content
local second_part = ai_content

-- == Write to the ai_content_for_raw
local ai_content_for_raw = "====\n> Info: " .. ai_response.info .. "\n\n" .. ai_content .. "\n\n"
utils.file.append(data.ai_responses_for_raw_path, ai_content_for_raw)

-- == Write to the src file
if data.context_files ~= nil then
    local blocks, other_content = utils.md.extract_blocks(ai_content, {extrude = "content"})
    -- In this case, the other_content becomes the second_part
    second_part = other_content
    msg = "Files updated: "
    for _, block in ipairs(blocks) do
        local first, remain = utils.text.split_first(block.content, "\n")
        local file_path = first:match(" file:%s*([^%s]+)")
        if file_path then 
            file_path = utils.path.join(base_dir,file_path)
            utils.file.save(file_path, remain)
            msg = msg .. file_path .. " " 
        end
    end
end

-- == Append to the second_part to ai_content_for_prompt file
second_part = utils.text.trim_start(second_part)
local ai_content_for_prompt = "====\n> Info: " .. ai_response.info .. "\n\n" .. second_part .. "\n"
utils.file.append(data.ai_responses_for_prompt_path, ai_content_for_prompt)

-- == Update the prompt file
local first_part = utils.text.trim_end(data.first_part)

local ai_content_for_prompt = utils.file.load(data.ai_responses_for_prompt_path).content
local prompt_content = first_part .. "\n\n" .. ai_content_for_prompt

utils.file.save(data.prompt_path, prompt_content)

-- This will be printed by devai if it is a string
return msg
```