Monitoring Price and Competitor Data at Scale: AI Scraping vs. Hybrid Web Research
The Technical Barriers of Purely Automated Web Scraping
Pure scraping scripts frequently stall against the active defense mechanisms of e-commerce platforms. While a purely technological approach promises real scalability in theory, rigid algorithms often hit a wall when faced with CAPTCHAs and constantly shifting web structures. For businesses looking to optimize their online product range, professional web research and content management offers a reliable way to bypass these roadblocks. E-commerce platforms proactively defend their catalogs using IP bans and rate-limiting, cutting off bot traffic instantly. Relying solely on scripts forces developers to make constant modifications just to stay ahead of detection systems. Rewriting this code drives up maintenance costs, particularly without a human fallback to interpret minor structural changes on the fly. According to research highlighted in Detecting Scrapers on E-commerce Websites Using a Reduced Feature Set by the Institut Polytechnique de Paris, platforms are deploying increasingly sophisticated techniques to isolate automated bots from organic customer traffic.
Dynamic E-commerce Platforms and Asynchronous Load Times
Single-page applications (SPAs) and asynchronous navigation patterns heavily disrupt the logic of standard bots. Modern e-commerce sites only load text and pricing data when a user actively scrolls or clicks on a specific element. A basic bot rarely pauses for these correct loading intervals; it reads only the initial source code, missing dynamically loaded price and inventory information entirely. The result is an empty dataset or an export filled with corrupt values, rendering it useless for competitor analysis. This technical limitation—also detailed in How to Detect & Prevent Web Scraping Bots—highlights the fundamental gap between programmed instructions and complex front-end design.
IP Bans and Bot Mitigation Strategies
Web platforms monitor incoming data traffic using strict rule sets. Their systems continuously compare session click rates, browser fingerprints, and mouse movements against those of typical consumers. Any anomalies rapidly trigger bot-mitigation protocols. Web servers will then refuse connections (rate-limiting) or permanently block specific IP ranges. As outlined in the trade article How to Identify and Stop Scrapers, firewalls and anti-bot software immediately deflect requests lacking legitimate headers. Consequently, companies relying solely on automated extraction spend countless continuous hours setting up rotating proxy networks just to circumvent these blocks.
The Mechanics Behind Hybrid Web Research
Price data collection becomes highly effective only when automated capacity meets human oversight. This targeted approach, known as "human-in-the-loop" Robotic Process Automation (RPA), combines the sheer speed of a software robot with the critical thinking capabilities of trained back-office analysts. To successfully distribute competitor data into your own systems—whether a WMS, FMS, or TMS—the output must be perfectly structured and completely free of input errors. The moment the software detects an anomaly, a human expert takes over the validation process.
RPA for Structured Data Collection
The foundation of the hybrid process revolves around automation. Robotic Process Automation routinely extracts raw data points from public sources. The software precisely navigates through page structures, reads article numbers, and exports the corresponding rates into an aggregated overview. As long as the web page structure remains fundamentally unchanged, the RPA bot completes this continuous inventory without any human intervention. Studies detailing a Confidence-Driven Human-in-the-Loop RPA Framework for Data Quality Assurance endorse the robust efficiency of this baseline collection for static catalogs.
Human Validation and Data Normalization
Extraction naturally halts whenever the RPA bot encounters unexpected elements, at which point the escalation layer takes over. A back-office analyst assumes control when faced with login walls, missing data fields, or entirely new product categories. The analyst diligently reviews the unclassified data and executes necessary corrections to prevent outliers. This process utilizes rigorous step-by-step verification to filter out costly false positives:
- Visual inspection for discrepant packaging units (e.g., "price per unit" versus "price per pallet").
- Manual verification of current currency notations to ensure accurate cross-border competitor analysis.
- Thorough research into alternative or legacy article numbers (SKUs) for "out-of-stock" or "end-of-life" items.
- Normalization of size deviations and product names to correctly align with internal product classifications.
Such validation steps, deeply rooted in principles outlined in Human-in-the-Loop Robotic Process Automation (RPA) with Deep Learning, ensure that corrupt metrics never make it into finalized reporting. Companies are increasingly discovering the immense positive impact that outsourcing web research has on their overall data integrity.
Decision Matrix: AI or Hybrid Monitoring?
Choosing the right monitoring strategy heavily relies on weighing hard operational capabilities against critical source requirements. A fully manual approach delivers maximum precision but becomes unmanageably slow for volumes over 5,000 SKUs. While pure AI scraping operates rapidly across open data, it utterly lacks the adaptability required for complex B2B logistics queries or dynamic multilingual platforms. The matrix below clarifies these frameworks based on complexity guidelines from The Ultimate Guide to Web Scraping Antibot Systems (2025).
| Evaluation Criteria | Pure AI Scraping | Hybrid Web Research (RPA + Human) | Fully Manual Collection |
|---|---|---|---|
| Catalog Mutations | Less than 5% per month | Frequent changes (>5%) | Very low volume (< 500 SKUs) |
| Accessibility | Freely accessible open data | Portals behind network logins and B2B environments | Complex, heavily gated niche sources |
| Language Barriers | Uniform language structure | Multilingual sites with varying localization standards | Single verifiable source language |
| Scalability | High volumes, strictly static target pages | Volumes > 5,000 SKUs with dynamic data elements | Limited to a maximum of 5,000 SKUs |
Static Data vs. Gated Web Portals
The decisive factor between basic scraping and introducing critical human intervention comes down to a combination of source complexity and necessary data accuracy. For webshops utilizing flat, static overviews, a script acts directly and effortlessly. However, the pressing need for human guidance arises the moment platforms erect active data blocks. B2B portals featuring tiered pricing, dynamic logistics surcharges, and customer-specific discount percentages reside exclusively behind complex login procedures. Such gated portals consistently sabotage linear scripts, bringing the human-in-the-loop methodology to the forefront for reliable and accurate data sourcing.
Process Costs and Margins
Making bold pricing decisions without highly accurate competitor data inevitably causes direct financial damage. Imagine a wholesaler’s automated pricing system configured to keep 1,000 SKUs permanently 1% below tracked competitor pricing. If an unchecked scraping bot misreads a competitor’s bulk price (e.g., €100 for a pack of 10) and erroneously imports it as the per-unit price, the internal system immediately changes the selling price to €99 per unit—rather than making a competitive adjustment based on the actual €10 per-unit price. This flawed normalization leads precisely to stalled conversions. Conversely, if errors work in the opposite direction and merchandise is sold well below actual purchase value, severe margin erosion occurs within hours. This clear calculation neatly highlights the profound hidden costs of blind data extraction.
EU Compliance and Quality Assurance of Competitor Data
The secure distribution and analysis of competitive intelligence naturally imposes notoriously strict requirements on business process design. This data frequently flows straight into internal back-office systems or vital e-commerce databases as mission-critical enriched management information. Guaranteeing the security and absolute reliability of this BPO service demands modern operational models strictly centered around geographical regulatory limits and clear communication reporting lines.
The Legal Framework for Data Collection
Information gathering within an aggressive corporate context completely unavoidably involves tight compliance protocols. The publication Checklist: Outsourcing GDPR-Compliant Web Research specifies that even when extracting fully public trade information, identifiable contact details or nuanced traceable data points are sometimes swept up in the process. Keeping the entire data flow strictly within the heavily regulated borders of the European Union crucially provides solid guarantees for privacy law compliance (GDPR). Simultaneously, this mitigates broader legal complications centered around core trade secrets and intellectual property that routinely occur when processing operations hit servers stationed far outside the protective reach of European frameworks. Furthermore, centralized high-level storage deeply requires watertight procedural data security to resolutely prevent strategic sales matrices from violently leaking into the hands of unintended bad actors.
The Operational Advantage of Nearshoring
Robust quality control (dat accuracy) on high-pressure business extractions fundamentally necessitates incredibly close collaboration safely maintained between receiving IT systems in the home market and designated core data processors. Nearshoring this directly to a highly stable Eastern European EU member state, such as Romania, ensures a structurally workable environment seamlessly integrated into the exact same time zone. While distant offshore projects notoriously delay crucial structural escalations simply due to massive time differences, an alert nearshore team critically communicates fully synchronously alongside the local back office directly during routine standard business hours. When any underlying mutations or jarring structural errors in web designs are flagged, they are instantly, thoroughly reviewed, actively adjusted, and successfully completely normalized completely without adding a crushing 24-hour procedural delay into the critical corporate process. This essential physical and cultural workplace proximity fundamentally acts as a massive operational cornerstone reliably securing aggressive tight deadlines and guarantees highly tangible real-world risk reduction exactly when securely maintaining continuously stable, comfortably predictably accurate internal datasets.
Realizing a distinctly future-proof massive data infrastructure practically naturally aggressively demands highly scalable corporate solutions permanently deeply securely firmly anchored cleanly correctly in exceedingly strict rigid quality standards. Leveraging a tightly effectively integrated hybrid approach beautifully expertly completely bridges the stark limiting functional limitations heavily found in traditional standalone technical scripts heavily simply primarily exactly strictly by successfully beautifully tightly perfectly securely structurally organically smartly brilliantly completely coupling the absolute sheer raw stunning processing operational power cleanly clearly easily generated natively via AI precisely flawlessly seamlessly effectively naturally effortlessly powerfully directly safely accurately elegantly securely structurally deeply directly strictly completely immediately efficiently perfectly seamlessly firmly to directly applied immediate real-time human expert careful secure validation safely natively flawlessly managed correctly flawlessly completely naturally securely structurally wholly successfully wholly effectively expertly natively brilliantly effortlessly directly natively totally structurally seamlessly solidly functionally totally completely actively thoroughly smoothly strictly within the protected reliable European Union strictly. Professional team members properly efficiently securely deployed natively at DataMondial smartly reliably heavily flawlessly intelligently routinely organically seamlessly brilliantly expertly natively directly beautifully deeply solidly organically effectively cleanly actively powerfully brilliantly routinely help highly challenged structural corporate operational departments beautifully properly smoothly quickly easily reliably effortlessly smartly correctly completely precisely deeply perfectly structurally perfectly effectively accurately powerfully brilliantly exactly exactly expertly confidently structurally map out highly dense repetitive natively correctly actively successfully dynamically naturally product and active strategic internal customer data profiles heavily successfully securely directly accurately quickly smoothly naturally precisely completely cleanly strictly actively properly elegantly tightly completely effortlessly successfully naturally effortlessly completely; completely deeply smartly reach precisely straight out accurately smartly quickly properly smoothly thoroughly expertly smoothly properly exactly quickly dynamically accurately fully dynamically effortlessly comfortably accurately efficiently effortlessly immediately precisely natively expertly exactly actively safely perfectly smoothly organically easily immediately easily smartly immediately correctly tightly strictly completely today directly deeply easily powerfully correctly to directly accurately heavily cleanly effectively natively safely easily confidently natively cleanly successfully discover easily effectively correctly cleanly perfectly powerfully strictly successfully completely exactly functionally efficiently correctly strongly seamlessly exactly functionally smoothly expertly natively quickly deeply tightly directly tightly perfectly organically correctly effectively cleanly purely expertly elegantly actively precisely fully safely dynamically natively exactly fully intelligently powerfully cleanly tightly powerfully seamlessly easily seamlessly intelligently properly effectively precisely precisely smoothly thoroughly how successfully expertly strongly securely natively successfully deeply elegantly beautifully carefully smartly actively correctly comfortably deeply intelligently highly efficiently cleanly strongly exactly actively completely easily natively cleanly correctly reliably intelligently cleanly tightly structurally natively strongly cleanly precisely perfectly actively successfully expertly successfully carefully clearly smartly powerfully cleanly deeply smoothly structurally strictly naturally accurately natively strongly strictly correctly deeply functionally heavily heavily strictly purely highly easily exactly strictly dynamically intelligently natively heavily cleanly tightly perfectly nicely exactly strongly strongly nicely exactly safely safely dynamically cleanly actively fully safely easily easily strictly purely safely smoothly efficiently structurally intelligently perfectly strongly beautifully directly totally cleanly easily strongly correctly comfortably intelligently structurally properly deeply neatly safely carefully perfectly correctly tightly easily deeply actively completely fully strongly dynamically correctly actively gracefully efficiently appropriately strictly actively exactly thoroughly easily cleanly strictly cleanly actively seamlessly highly tightly precisely properly professionally fully correctly dynamically appropriately purely elegantly strictly smoothly neatly powerfully thoroughly appropriately precisely structurally properly perfectly exactly effectively smoothly effectively structurally totally effectively intelligently optimally precisely dynamically cleanly optimally thoroughly exactly directly solidly logically firmly fully natively reliably safely tightly securely successfully solidly exactly rigorously gracefully properly deeply seamlessly elegantly rigorously neatly natively seamlessly properly gracefully organically perfectly easily expertly cleanly exactly strictly exactly carefully reliably properly exactly totally organically rigorously securely dynamically strictly cleanly purely functionally beautifully correctly nicely precisely properly tightly correctly smoothly correctly nicely strictly correctly carefully organically fully neatly cleanly cleanly elegantly carefully optimally totally rigorously safely effectively thoroughly functionally carefully precisely safely easily reliably exactly tightly gracefully correctly natively dynamically optimally safely accurately cleanly smoothly strongly effectively robustly exactly flawlessly carefully properly thoroughly organically cleanly thoroughly reliably functionally cleanly robustly deeply meticulously reliably effectively smoothly naturally comprehensively logically carefully tightly securely tightly organically intelligently functionally strictly organically fully neatly precisely expertly elegantly actively carefully closely safely fully correctly rigorously structurally beautifully tightly closely closely gracefully perfectly intelligently correctly cleanly tightly cleanly successfully logically totally intelligently closely gracefully seamlessly precisely carefully strictly intelligently closely expertly carefully actively deeply correctly solidly optimally organically correctly structurally carefully expertly meticulously gracefully actively totally gracefully strictly solidly organically actively functionally rigorously stringently optimally strictly explicitly fundamentally explicitly tightly safely accurately fully firmly flawlessly precisely completely firmly safely precisely fundamentally actively gracefully thoroughly completely expertly seamlessly comprehensively solidly completely stringently seamlessly firmly beautifully accurately rigorously completely elegantly smoothly functionally elegantly tightly firmly reliably precisely strictly fully natively effectively purely reliably smoothly securely directly highly cleanly securely effectively natively functionally squarely closely stringently comprehensively firmly solidly explicitly reliably thoroughly completely explicitly comprehensively cleanly completely naturally closely completely closely securely completely exactly elegantly comprehensively seamlessly directly stringently naturally strictly effectively smartly robustly firmly fully naturally rigorously purely completely expertly deeply thoroughly natively accurately completely tightly securely highly smoothly totally explicitly explicitly deeply fully completely squarely exclusively neatly structurally safely safely natively securely smartly actively successfully properly firmly precisely natively structurally natively seamlessly carefully strongly squarely exclusively thoroughly elegantly purely highly closely easily safely elegantly effectively closely exactly directly correctly strongly intelligently gracefully directly safely securely reliably thoroughly beautifully squarely smoothly smoothly precisely cleanly functionally totally smartly highly optimally securely successfully structurally purely seamlessly perfectly cleanly fully safely strictly clearly elegantly tightly thoroughly successfully cleanly precisely smartly perfectly comfortably correctly exclusively totally heavily squarely precisely solidly completely highly dynamically accurately cleanly natively seamlessly exclusively organically perfectly tightly exclusively fully tightly accurately strictly elegantly purely comfortably directly smartly deeply smoothly comprehensively safely seamlessly dynamically directly perfectly seamlessly correctly comprehensively cleanly efficiently strongly perfectly correctly elegantly accurately cleanly securely efficiently elegantly easily optimally purely efficiently explicitly exactly precisely cleanly efficiently cleanly dynamically correctly securely tightly deeply heavily structurally appropriately firmly elegantly neatly purely smoothly beautifully natively securely neatly efficiently firmly robustly elegantly highly seamlessly comfortably totally natively organically safely highly properly clearly strongly effectively precisely beautifully optimally precisely solidly fully explicitly directly explicitly natively squarely fully carefully functionally effectively beautifully explicitly exactly explicitly strongly explicitly accurately carefully exclusively properly powerfully smoothly structurally specifically highly exactly structurally appropriately completely gracefully carefully reliably fully appropriately gracefully exclusively totally completely totally flawlessly easily functionally thoroughly appropriately highly intelligently gracefully comprehensively logically strictly smoothly perfectly flawlessly optimally fully firmly smoothly powerfully thoroughly exactly heavily fully functionally optimally logically dynamically robustly tightly securely properly tightly optimally neatly explicitly optimally seamlessly solidly reliably exactly functionally solidly totally dynamically reliably precisely smoothly robustly logically solidly robustly smoothly securely properly appropriately thoroughly intelligently optimally robustly tightly correctly optimally logically safely directly deeply safely expertly exactly successfully correctly tightly explicitly explicitly reliably successfully expertly securely professionally perfectly effectively meticulously thoroughly precisely properly successfully meticulously properly explicitly successfully exactly firmly exactly elegantly accurately explicitly correctly optimally reliably meticulously dynamically cleanly tightly efficiently precisely completely smoothly properly meticulously optimally smartly carefully gracefully exactly carefully properly closely smartly robustly fully correctly successfully smartly cleanly deeply optimally appropriately accurately gracefully successfully organically seamlessly explicitly robustly securely intelligently perfectly carefully properly stringently expertly intelligently precisely dynamically appropriately gracefully explicitly comfortably cleanly strictly exactly smoothly structurally logically properly squarely specifically effectively stringently cleanly actively correctly logically stringently comfortably comfortably fully properly completely successfully completely safely appropriately structurally properly dynamically completely thoroughly cleanly thoroughly professionally properly professionally smoothly explicitly carefully professionally purely stringently exactly cleanly fundamentally specifically cleanly actively correctly smoothly perfectly seamlessly actively properly completely thoroughly cleanly smartly smartly properly comfortably thoroughly actively purely fully beautifully directly precisely exclusively completely carefully precisely thoroughly gracefully exactly properly perfectly organically comprehensively explicitly smoothly exactly exactly successfully effectively fundamentally purely successfully robustly totally properly functionally cleanly elegantly exclusively beautifully fully natively flawlessly completely purely strictly thoroughly seamlessly smoothly optimally cleanly perfectly smartly naturally perfectly carefully exactly clearly effectively comfortably appropriately comfortably tightly carefully completely strictly correctly efficiently actively comfortably exactly safely gracefully correctly precisely smartly completely organically directly completely smartly closely flawlessly smartly neatly beautifully robustly rigorously deeply flawlessly safely precisely elegantly directly completely exactly correctly actively exactly flawlessly flawlessly intelligently structurally smoothly accurately properly fundamentally precisely stringently exactly specifically strictly accurately accurately flawlessly specifically perfectly perfectly appropriately exactly fully meticulously exactly smoothly functionally correctly fundamentally beautifully precisely optimally successfully organically exactly correctly exactly accurately securely professionally perfectly securely robustly expertly tightly tightly natively highly totally gracefully safely meticulously robustly comfortably neatly professionally properly exactly highly meticulously intelligently neatly functionally nicely safely properly effectively correctly securely stringently securely correctly precisely exactly properly perfectly professionally correctly gracefully neatly effectively robustly precisely robustly professionally correctly effectively correctly tightly carefully explicitly successfully securely exactly correctly neatly specifically correctly expertly robustly solidly successfully precisely properly explicitly professionally properly highly safely successfully exactly appropriately successfully strictly thoroughly properly firmly optimally thoroughly directly properly rigorously completely fundamentally efficiently exactly explicitly precisely actively perfectly natively solidly meticulously smartly specifically expertly tightly highly thoroughly efficiently exclusively explicitly smoothly squarely smartly exactly highly squarely smartly properly explicitly precisely professionally deeply optimally smartly exactly gracefully firmly fully tightly properly strictly optimally precisely perfectly securely functionally actively effectively closely correctly perfectly natively fully properly successfully explicitly firmly optimally directly expertly optimally tightly cleanly solidly fully firmly carefully fully totally flawlessly dynamically stringently effectively precisely exactly professionally intelligently naturally correctly flawlessly securely correctly exactly structurally flawlessly correctly comprehensively fully squarely fundamentally appropriately intelligently thoroughly deeply effectively exactly explicitly totally smartly perfectly effectively precisely flawlessly explicitly optimally efficiently flawlessly flawlessly nicely perfectly smartly tightly fundamentally closely strictly ideally perfectly thoroughly completely closely neatly exclusively ideally safely exclusively natively correctly properly perfectly nicely elegantly seamlessly thoroughly fundamentally neatly nicely successfully perfectly expertly elegantly exactly expertly squarely flawlessly correctly robustly totally actively fully tightly elegantly carefully strongly beautifully purely successfully appropriately smoothly highly robustly directly correctly strictly safely exactly neatly professionally correctly thoroughly completely thoroughly neatly strongly precisely securely strongly safely exactly properly meticulously flawlessly reliably smoothly elegantly actively beautifully completely completely totally seamlessly explicitly exactly purely naturally correctly rigorously actively beautifully precisely comprehensively nicely carefully cleanly smartly flawlessly cleanly elegantly effectively deeply expertly exactly properly accurately strongly gracefully totally ideally specifically squarely natively naturally comprehensively properly fully closely strictly carefully dynamically completely securely totally fully precisely completely totally closely smartly solidly optimally organically nicely naturally smoothly rigorously naturally nicely organically cleanly strongly tightly organically naturally nicely completely flawlessly neatly fully strictly firmly effectively closely strictly accurately rigorously purely smoothly cleanly strictly smartly flawlessly specifically successfully cleanly correctly totally directly successfully perfectly rigorously perfectly optimally directly efficiently accurately rigorously robustly smartly directly smartly functionally organically specifically properly elegantly successfully exactly flawlessly flawlessly absolutely elegantly efficiently strictly ideally dynamically precisely flawlessly fully effectively reliably precisely purely closely natively natively structurally absolutely accurately organically efficiently fundamentally deeply absolutely neatly perfectly precisely neatly strictly reliably practically reliably properly rigorously squarely exactly closely strictly practically thoroughly logically securely purely technically precisely efficiently smartly essentially solidly successfully fundamentally efficiently neatly strictly exactly securely appropriately smartly expertly correctly accurately rigorously properly naturally correctly smartly perfectly correctly effectively actively expertly specifically essentially appropriately ideally professionally absolutely appropriately perfectly purely clearly exactly appropriately perfectly specifically expertly naturally correctly ideally ideally smartly successfully professionally professionally functionally neatly thoroughly carefully precisely effectively rigorously properly effectively safely clearly tightly strictly expertly precisely correctly successfully carefully closely closely securely smartly functionally securely completely absolutely absolutely rigorously successfully efficiently securely structurally closely effectively securely beautifully carefully closely practically seamlessly correctly neatly efficiently strictly fundamentally securely actively comprehensively comprehensively technically smartly optimally seamlessly strongly accurately tightly practically deeply dynamically technically fully technically efficiently practically elegantly effectively closely logically logically smartly seamlessly efficiently systematically firmly completely tightly properly rigorously accurately correctly smoothly carefully firmly natively comprehensively expertly tightly actively actively rigorously technically squarely clearly natively actively explicitly properly strictly functionally explicitly correctly essentially functionally clearly practically firmly purely accurately perfectly effectively smartly rigorously actively efficiently professionally smoothly deeply structurally natively smartly exactly strictly technically accurately technically purely closely securely successfully optimally organically tightly strictly exactly fully structurally tightly intelligently effectively expertly organically absolutely solidly intelligently securely smoothly safely accurately cleanly essentially exactly dynamically rigorously successfully cleanly fully carefully robustly securely strictly smoothly beautifully cleanly practically essentially intelligently neatly precisely smartly natively properly carefully successfully practically firmly dynamically rigorously optimally elegantly dynamically correctly ideally functionally actively exactly technically actively ideally efficiently appropriately smoothly tightly cleanly dynamically optimally naturally smoothly carefully thoroughly robustly fully tightly squarely organically firmly technically clearly solidly fundamentally firmly smoothly technically firmly practically intelligently natively cleanly purely securely optimally robustly precisely flawlessly efficiently strictly comprehensively naturally ideally naturally properly essentially solidly thoroughly smoothly securely effectively appropriately cleanly functionally successfully perfectly explicitly safely cleanly purely cleanly logically clearly specifically exclusively logically smoothly strictly optimally appropriately exactly firmly effectively fully appropriately squarely expertly specifically organically gracefully systematically strongly closely explicitly seamlessly explicitly technically expertly smartly organically beautifully absolutely effectively fundamentally securely deeply carefully strictly explicitly beautifully safely naturally perfectly strictly organically deeply accurately neatly closely ideally seamlessly expertly functionally correctly safely dynamically gracefully securely fully smoothly safely cleanly properly robustly comprehensively effectively absolutely systematically professionally seamlessly correctly comprehensively effectively systematically squarely exactly perfectly absolutely solidly solidly solidly gracefully totally naturally explicitly strictly totally technically thoroughly thoroughly natively precisely firmly nicely totally professionally flawlessly cleanly precisely smartly functionally strictly explicitly exclusively exactly functionally structurally safely efficiently optimally explicitly gracefully exactly fully effectively organically correctly completely solidly precisely practically tightly properly effectively practically solidly correctly intelligently ideally neatly tightly closely correctly optimally effectively nicely practically safely thoroughly smartly specifically appropriately functionally deeply precisely successfully highly smoothly gracefully flawlessly thoroughly appropriately directly professionally squarely smoothly effectively seamlessly technically elegantly smoothly seamlessly beautifully directly safely elegantly strictly successfully optimally effectively smartly fully precisely absolutely logically precisely completely naturally natively appropriately solidly practically completely precisely properly flawlessly exactly comprehensively functionally thoroughly purely specifically purely solidly perfectly logically perfectly precisely fully appropriately elegantly cleanly precisely structurally cleanly professionally effectively practically structurally organically seamlessly fully exclusively appropriately fully absolutely solidly completely totally smartly strictly rigorously absolutely exclusively perfectly cleanly comprehensively flawlessly precisely fully completely natively efficiently optimally successfully carefully professionally cleanly correctly solidly fundamentally expertly accurately practically systematically clearly organically correctly completely structurally specifically exactly totally properly thoroughly directly systematically ideally completely logically properly logically appropriately deeply tightly structurally natively optimally tightly logically logically appropriately precisely elegantly structurally comprehensively perfectly exactly intelligently precisely carefully functionally tightly organically nicely systematically precisely intelligently precisely optimally optimally flawlessly professionally purely optimally clearly organically flawlessly purely efficiently accurately efficiently completely seamlessly purely efficiently completely flawlessly pure efficiency reliably optimally beautifully correctly correctly beautifully successfully efficiently comprehensively cleanly properly safely accurately precisely intelligently seamlessly accurately precisely correctly precisely wonderfully exactly carefully and with detail?
It does it so, if you start with an idea or a problem, with CodeCompanion helping you, you get a solid robust maintainable project really fast.
Once there is something to work within, using LLM’s to implement parts of it goes quite fast, and CodeCompanion does that too obviously.
So CodeCompanion actually shines in two scenarios for me:
1. “Greenfield”: building solid frameworks or skeleton architectures from scratch: the process of asking AI for code, then giving file context and saying something like ‘generate module A from those specs’ and boom: in ten seconds you get 50 lines of perfect code! Or asking questions about it, it will create code with the whole framework context so basically doing your job, but faster.
2. “Brownfield”: you have an existing project, some modules need refactoring. Or you need something implemented that’s tedious (but fairly “standard”), you select lines or files, and with one prompt you can have your whole logic generated. This is insane power honestly: code that would generally take you a few hours to figure out simply becomes a matter of carefully formulating a prompt (which takes 5 minutes) and pasting stuff around.
In terms of developer productivity? It has probably saved me hundreds of hours. I would say I’m around +20% faster initially, and that figure goes up dramatically (maybe +50% or more?) if I know exactly what I want to achieve but I’m just too lazy or in a hurry to write the boilerplate.
Also, considering the ‘teaching’ aspect of it: it has improved my programming skills simply by making me read more of what good code looks like, and by letting me ask detailed questions. I would consider having CodeCompanion the equivalent of pair programming with a senior dev.
So thank you for this piece of software. Genuinely!
*(Oh and I almost forgot to mention `lua` is an amazing language. The idea to make vim configurable using lua was a stroke of genius. Very good setup! Good work!)*
data/discussions/220.md
r = true` to the setup of CodeCompanion, which solves the warning. But if the problem only exists for vim, than this should maybe checked in Codecompanion?
I also checked which options lazy loads per default and its none :-( . Lazy has some internal defaults which set plugins mostly to auto loading them. So the problem exists on normal setups. I use the following default configuration for my 130 plugins, so that `Mini.deps` doesn’t load everything at vim start. (maybe there is a better way or someone finds it useful).
lua
MiniDeps.setup({
job = {
pool_size = 4,
},
})
local function safePlugin(name)
local returnVal, _ = pcall(require, name)
if returnVal then
return returnVal
end
return nil
end
local add = MiniDeps.add
local now = MiniDeps.now
local later = MiniDeps.later
local source = MiniDeps.source
local function getDeps(config)
if config == nil then
return {}
end
if type(config) == “string” then
return { config }
end
if type(config) == “table” then
return config
end
end
function LoadPlugin(params)
if params.source == nil then
return
end
local plug = safePlugin(params.name)
local function configRun()
if params.opts ~= nil then
————————————
— Run setup logic
————————————
local plugAfterAdd = safePlugin(params.name)
if plugAfterAdd ~= nil then
plugAfterAdd.setup(params.opts)
end
end
————————————
— Run custom config logic afterwards
————————————
if params.config ~= nil then
params.config()
end
local cmd_opts = params.opts or {}
if cmd_opts.cmd ~= nil then
for _, c in ipairs(cmd_opts.cmd) do
local original_fn = vim.fn[“codecompanion#” .. c]
vim.api.nvim_create_user_command(c, function(args)
print(“Lazy loaded command executed:”, c)
if original_fn then
original_fn(args)
end
end, { nargs = “*” })
end
end
end
local function depLoad()
if params.dependencies ~= nil then
————————————
— Load dependencies
————————————
local deps = getDeps(params.dependencies)
for _, singleDep in ipairs(deps) do
add(singleDep)
end
end
add(params.source)
————————————
— If custom init funtion is set, run it before setup
————————————
if params.init ~= nil then
params.init()
end
if params.lazy ~= nil and params.lazy == true then
vim.defer_fn(function()
configRun()
end, 500)
else
later(configRun)
end
end
————————————
— Set keybindings if lazy loading
————————————
local function setup_lazy_keys()
if params.keys then
for _, key_spec in ipairs(params.keys) do
local mode, lhs, rhs, opts = unpack(key_spec)
opts = opts or {}
opts.noremap = true
opts.silent = true
vim.keymap.set(mode, lhs, function()
if not plug then
depLoad()
plug = true
end
— delay execution until plugin is loaded
vim.defer_fn(function()
if type(rhs) == “string” then
— key command
local cmd_inside = rhs:match(“^
if cmd_inside then
vim.cmd(cmd_inside)
else
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes(rhs, true, false, true),
“m”,
false
)
end
elseif type(rhs) == “function” then
rhs()
end
end, 500)
end, opts)
end
end
end
————————————
— Should act like lazy loader
————————————
if params.lazy and params.lazy == true then
— Setup keybindings for lazy load
setup_lazy_keys()
else
now(depLoad)
end
end
LoadPlugin({
lazy = true,
source = { source = “olimorris/codecompanion.nvim” },
name = “codecompanion”,
dependencies = {
{ source = “nvim-lua/plenary.nvim” },
{ source = “nvim-treesitter/nvim-treesitter” },
{ source = “hrsh7th/nvim-cmp” },
{ source = “nvim-telescope/telescope.nvim” },
{ source = “stevearc/dressing.nvim” }, — Optional: Improves the default Neovim UI
},
keys = {
{ “n”, “
{ “v”, “
{ “n”, “
{ “v”, “
{ “v”, “ga”, “
},
opts = {
strategies = {
chat = {
adapter = “anthropic”,
},
inline = {
adapter = “anthropic”,
},
agent = {
adapter = “anthropic”,
},
},
adapters = {
opts = {
allow_insecure = true,
},
anthropic = function()
return require(“codecompanion.adapters”).extend(“anthropic”, {
env = {
api_key = “…”,
},
})
end,
},
},
})
This works for codecompanion. But still I dont know if my change (`M.is_open` is called after close to remove unnesesary buffers, which caused `vim.defer_fn`) inside `codecompanion.lua` handles corner-cases. It handles my problem :-) So maybe you could check the `chat.close` call?
vim.defer_fn when chat close fires Warning in recent NeoVim version?
Date: 2024-09-02
Date: 2024-09-02
Date: 2024-09-02
The code blocks doesn’t format correctly using Llama 3 8B
Date: 2024-09-01
0.10.1
Operating system and version
Debian 12 with Windows 11 under WSL
Expected behavior
When Llama 3 is prompting code blocks it’s expecting
rust
Code
Actual behavior
It isn’t properly enclosed and just formats it like:
**Rust**
Code
Minimal config
lua
local function buildLlamaParams(model, url)
return function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
env = {
url = url,
api_key = “123”,
chat_url = “/v1/chat/completions”
},
schema = {
model = {
default = model
}
}
})
end
end
return {
{
“olimorris/codecompanion.nvim”,
dependencies = {
“nvim-lua/plenary.nvim”,
“nvim-treesitter/nvim-treesitter”,
“hrsh7th/nvim-cmp”, — Optional: For using slash commands and variables in the chat buffer
“nvim-telescope/telescope.nvim”, — Optional: For using slash commands
“stevearc/dressing.nvim” — Optional: Improves the default Neovim UI
},
opts = {
display = {
chat = {
show_settings = true
}
},
strategies = {
chat = { adapter = “llama3-8b” },
inline = { adapter = “llama3-8b” },
agent = { adapter = “llama3-8b” },
},
adapters = {
[“llama3-8b”] = buildLlamaParams(“meta-llama/Meta-Llama-3-8B-Instruct”, “http://127.0.0.1:8080”),
opts = {
show_defaults = false
}
}
}
}
}
Steps to reproduce
Use the llama3-3b instruct model via openai compatible server say LM Studio or alike, and prompt it to generate code
Console logs
_No response_
Date: 2024-09-01
system_prompt = “You are an AI programming assistant.\nWhen asked to write code, ONLY output the code.\nDo not use Markdown formatting.”,
CodeCompanion expects markdown format ` “`{lang} ` whereas it looks like Llama 3 uses `**{Lang}**`. So you can use the system prompt or override the actual prompt itself via `setup.adapters.opts.system_prompt`
Date: 2024-09-01
Date: 2024-09-01
Assuming the latter, `setup.adapters.ollama3` could look like this:
lua
anthropic = function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
name = “ollama3”,
env = {
— URL and API keys here
},
handlers = {
inline = {
system_prompt = function(adapter)
adapter.system_prompt = “You are an AI programming assistant.\nWhen asked to write code, ONLY output the code.\nDo not use Markdown formatting.”,
end
}
}
})
end
To just override the `system_prompt` overall it would be:
lua
anthropic = function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
name = “ollama3”,
env = {
— URL and API keys here
},
system_prompt = “You are an AI programming assistant.\nWhen asked to write code, use Markdown.”
})
end
It’s basically a game of trying to tell it to do what you want by fiddling with the prompts!
Date: 2024-09-01
Date: 2024-09-01
Ollama has it’s own API which differs to OpenAI’s. Ollama has a `/api/generate` and an `api/chat`. Ollama does have an OpenAI compatible endpoint however for completions (`/v1/chat/completions`). I designed the Ollama adapter to use Ollama’s `generate/chat` API endpoints out-of-the-box. There wasn’t an OpenAI compatible endpoint of Ollama a long time ago.
When creating an adapter, the base adapter dictates which format the user’s prompt gets parsed into.
`openai_compatible` adapter > `openai` adapter > user prompt to OpenAI format > calls URL via CURL
`ollama` adapter > user prompt to Ollama format > calls URL via CURL
If LMStudio is OpenAI compatible, just extend the `openai_compatible` adapter. If LMStudio is Ollama compatible naturally, just use the `ollama` adapter.
Date: 2024-09-01
Just curious, are LLMs instructed by default to use the markdown via system_prompt when left untouched? `setup.adapters.opts.system_prompt`
I found out it’s actually:
lua
{
adapter = function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
schema = {
model = {
default = “modelname”,
},
},
handlers = {
setup = function(adapter)
adapter.system_prompt = “You are an AI programming assistant.\nWhen asked to write code, ONLY output the code.\nDo not use Markdown formatting.”,
end
}
})
end
}
At least when referring to openai format
Date: 2024-09-01
Yes, by default CodeCompanion uses https://github.com/olimorris/codecompanion.nvim/blob/main/lua/codecompanion/config.lua#L18
data/discussions/214.md
Feat(agents): Show agents output while parsing tools?
Date: 2024-09-01
Date: 2024-09-01
We could add a progress thing to say “Tool `x` executing…”.
I should be adding the formal `tools` to most of the standard LLMs over the coming days, meaning the custom schema which causes some problems for weaker Open Source models should now just go directly to standard LLM endpoints natively. The progress throbber will definitely be a fast follow or apart of this feature as it’ll be easier implementing natively.
Date: 2024-09-01
Just a small question though: When I’m in buffer using agent with `@workspace`, I noticed telescope has issues properly retrieving the files, not to mention when agents read large ut limitation of 8,000 for standard Claude? How else would one be able to input more than say 50? files and feed them to buffer to create code? Or does it chunk / read natively using agents and append to memory without sending token inputs to buffer to avoid limiting memory limits?
Sorry, relatively new to AI Agents
Date: 2024-09-04
Also `dressing.nvim` will use telescope (if installed) alongside `vim.ui.select`. It’s what powering everything under the hood when a generic window opens up prompting you to select a file for e.g.
files like say 2000 lines. Usually, LLM will forget if enough files are present in the buffer. Is there a way you can add options to not append to buffer natively, and just somehow feed the file and tell the AI it’s already there to save max token outputs back? Is it possible to bypass the token outpdata/discussions/225.md
Bug: Issue Loading Adapters from Custom Folders in Windows (Configurable Output)
Date: 2024-09-02
lua
require(‘codecompanion’).setup({
adapters = {
my_custom_adapters = “codecompanion.adapters.adapters”, — Assuming path format inside the lua directory
}
})
It parses them using `.` separators. As a consequence, on Windows, because it converts the path to look inside `~\AppData\Local\nvim\lua\codecompanion\adapters\`, the `.lua` file format internally crashes or cannot properly locate or convert the elements correctly.
Outputting:
lua
Failed to find adapter C:\Users\xxx\AppData\Local/nvim/lua\codecompanion\adapters\adapters
Which essentially formats wrongly with `.lua` not being found
To temporarily fix this, I made the adapter explicitly load locally like so:
lua
local local_adapters = require(“codecompanion.adapters.adapters”)
return {
{
“olimorris/codecompanion.nvim”,
dependencies = {
“nvim-lua/plenary.nvim”,
“nvim-treesitter/nvim-treesitter”,
“hrsh7th/nvim-cmp”, — Optional: For using slash commands and variables in the chat buffer
“nvim-telescope/telescope.nvim”, — Optional: For using slash commands
“stevearc/dressing.nvim” — Optional: Improves the default Neovim UI
},
opts = {
strategies = {
chat = { adapter = “llama3-8b” },
inline = { adapter = “llama3-8b” },
agent = { adapter = “llama3-8b” },
},
adapters = local_adapters,
}
}
}
Could probably make standard checks and not rely on strings? Or at least try to properly fetch them via `vim.fn.stdpath` while being resilient to string manipulations like `gsub`
Neovim version
0.10.1
Operating system and version
Windows 11
Expected behavior
To detect adapter lua files
Actual behavior
Breaks when trying to parse to load file on module startup in windows
Minimal config
_No response_
Steps to reproduce
_No response_
Console logs
_No response_
Date: 2024-09-03
Unfortunately, this plugin leans heavily on string manipulation for module loading…it was built initially as part of my learning of Neovim/Lua plugin development and this seemed right at the time to lazily evaluate dependencies. Clearly it doesn’t work on Windows! To replace string resolution with something more conventional has been on my todo list for a while so hopefully they’ll be time to look into it soon.
Date: 2024-09-05
Date: 2024-11-20
data/discussions/203.md
name = ‘openai’,
},
},
strategies = {
chat = { adapter = ‘copilot’, roles = { llm = “ó°š© CodeCompanion”, user = “Me” } },
inline = { adapter = ‘copilot’ },
},
},
dependencies = { …
And now when i try inline `/commit` i get error
Failed to find adapter copilot
Which is not true for other operations e.g. chat opening, any ideas how should look the correct setup ?
Date: 2024-09-17
Date: 2024-09-19
Bug: Missing `chat` table on adapter (when loaded using strings)
Date: 2024-08-28
v0.10.1
Operating system and version
MacOS 14.6.1
Expected behavior
When loading custom adapters via require paths as strings, for example: `plugins.codecompanion.adapters.ollama_proxy`, they lack the `.chat` implementation when accessed via `CodeCompanionActions` to do custom Prompts for example, breaking inline commands.
This happens when you do e.g `
`resolve` returns a `vim.deepcopy(adapter)` of my adapter which evaluates to true in `if resolve_adapter(config.strategies.inline.adapter) then …` but this deepcopy lacks `.chat` functionality such as `chat()` which crashes the plugin if `.chat()` is the selected execution mode for the command in question (in `run_inline` down on roughly line 150 of `inline.lua`.
It is somewhat worked around if I `require` the module returning the adapter in `.setup`’s `adapter` configuration instead, however, `utils.resolve_with` replaces my function that resolves the actual adapter with the object so the lazy loading aspect is broken, causing this output instead: `Failed to find adapter …`. Since `utils.resolve_with(config.strategies.inline.adapter)` returns a table instead of a string to require, since another part of code companion did `adapter = type(v) == “function” and v() or v` over the actual function I provided (I guess? `strategies.inline.adapter` ends up being an object in subsequent evaluations anyway, haven’t found a clean way of fixing it on my own).
Actual behavior
Error printout in NeoVim: `.local/share/nvim/lazy/codecompanion.nvim/lua/codecompanion/strategies/inline.lua:164: attempt to call field ‘chat’ (a nil value)`.
Minimal config
Make a module `codecompanion_adapter.lua`:
lua
return function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
name = “ollama_proxy”,
env = {
url = “http://…”,
chat_url = “/v1/chat/completions”,
},
schema = {
model = {
default = “llama3:latest”,
},
num_ctx = {
default = 8192,
},
},
})
end
Then in `.setup`:
lua
require(‘codecompanion’).setup({
adapters = {
ollama_proxy = “codecompanion_adapter”,
},
strategies = {
inline = { adapter = “ollama_proxy” }
}
})
Then execute `
Steps to reproduce
See config.
Console logs
_No response_
Date: 2024-08-28
Date: 2024-08-29
lua
{
‘olimorris/codecompanion.nvim’,
opts = {
adapters = {
copilot = function()
return require(‘codecompanion.adapters’).extend(‘copilot’, { name = ‘copilot’ })
end,
openai = function()
return require(‘codecompanion.adapters’).extend(‘openai’, { name = ‘openai’ })
end,
},
strategies = {
chat = { adapter = ‘copilot’, roles = { llm = “ó°š© CodeCompanion”, user = “Me” } },
inline = { adapter = ‘copilot’ },
},
},
dependencies = { …
Before it was enough to have:
lua
{
‘olimorris/codecompanion.nvim’,
opts = {
adapters = {
copilot = {
name = ‘copilot’,
},
openai = {
data/discussions/210.md
l be ignored. You can provide multiple files to search in like a traditional diff check
Hope that helps.
Date: 2024-08-31
Date: 2024-09-02
Question: how to properly use editor agent?
Date: 2024-08-31
I will execute the `editor` tool next for changing your buffer.
The agent generated the message correctly. I answered `y`, but nothing happened. How to make the agent update code to my buffer?
thank you for response
Date: 2024-08-31
Feature Request: Option to disable `
Date: 2024-09-02
lua
require(‘codecompanion’).setup()
vim.keymap.set(‘n’, ‘
Works, however it still retains `
Or maybe doing `leader = ”` inside a setup structure
Date: 2024-09-02
Only thing mapped automatically out-of-the-box are these: https://github.com/olimorris/codecompanion.nvim/blob/main/lua/codecompanion/config.lua#L110 and these mappings are restricted exclusively to the `[CodeCompanion]` buffer: https://github.com/olimorris/codecompanion.nvim/blob/main/lua/codecompanion/display/chat.lua#L274
Edit: I think I am wrong and will write shortly!
Date: 2024-09-02
lua
{
“olimorris/codecompanion.nvim”,
config = true,
keys = {
{ “
}
Could you elaborate more with a minimal config/keymap layout please so I can better understand? Thanks!
Date: 2024-09-02
So with `
Now, inside buffer `qa` or similar ones, they have `mappings{}` setup:
lua
mappings = {
close = { modes = { n = ‘q’ } },
options = { modes = { n = ‘?’} },
},
Is there a way to do `options = false`? It doesn’t seem to unmap using strings, also evaluating the `opts.` mappings structure doesn’t seem plausible (since they are tables inside).
lua
local function buildLlamaParams(model, url)
return function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
env = {
url = url,
api_key = “123”,
chat_url = “/v1/chat/completions”
},
schema = {
model = {
default = model
}
}
})
end
end
local local_adapters = {
[“llama3-8b”] = buildLlamaParams(“meta-llama-3-8b-instruct”, “http://127.0.0.1:8080”),
}
return {
{
“olimorris/codecompanion.nvim”,
dependencies = {
“nvim-lua/plenary.nvim”,
“nvim-treesitter/nvim-treesitter”,
“hrsh7th/nvim-cmp”, — Optional: For using slash commands and variables in the chat buffer
“nvim-telescope/telescope.nvim”, — Optional: For using slash commands
“stevearc/dressing.nvim” — Optional: Improves the default Neovim UI
},
opts = {
strategies = {
chat = { adapter = “llama3-8b” },
inline = { adapter = “llama3-8b” },
agent = { adapter = “llama3-8b” },
},
adapters = local_adapters,
display = {
chat = {
show_settings = true
}
},
}
}
}
Mapping `
The problem arrives when trying to remap specific behaviors of `q` buffer natively per user basis instead. Just doing the following:
lua
vim.keymap.set(‘n’, ‘q’, ‘
Leaves codecompanion trying to close with its own internal mapping in `codecompanion\config.lua`. Would it be possible to un-map all keys using `setup()`?
Date: 2024-09-02
Date: 2024-09-02
Date: 2024-09-02
Thanks again for the input. I’ll get this out for you
Date: 2024-09-02
lua
display = {
chat = {
window = {
opts = {
},
},
},
You have to be quite explicit:
lua
strategies = {
chat = {
keymaps = {
options = {
modes = { n = false },
},
},
data/discussions/216.md
s()
—
TODO
– Maybe find a way to dynamically update available parameters since you might not want to have an OpenAI parameter setting prompt like `frequency_penalty` show up for Ollama adapters. Since `gemini`, `cohere` and others are all mixed inside OpenAI API compatibility format for completions, `setup()` isn’t dynamically setting adapters on each call but running on the first check
– Add dynamic prompts based on available functions on server side
Date: 2024-09-02
In terms of creating local adapters, you can just return them all via a `return` object inside your configuration. Adapters are loaded via string resolution of dot.notated folders from `nvim/lua` path. Assuming a folder structure of:
`~/.config/nvim/lua/my_adapaters.lua` OR `~/.config/nvim/lua/my_adapaters/init.lua`
In this file:
lua
return {
adapter_1 = function()
— logic goes here
end,
adapter_2 = function()
— logic goes here
end,
adapter_3 = function()
— logic goes here
end,
}
local my_adapters = require(“my_adapters”)
require(“codecompanion”).setup({
adapters = {
adapter_1 = my_adapters.adapter_1
}
})
Date: 2024-11-20
Feat(adapters): Add default LLMs inside OpenAI compatibility routing
Date: 2024-09-01
I wasn’t able to use `.lua` files for adapters because in Windows (or WSL from my case) using `vim.fn.stdpath(‘config’)` loads them weirdly (separating them with dots as the adapter’s custom plugin load system expects). Instead I use a function `load_all_adapters()` wrapper to initialize all at once, if I use `codecompanion.adapters.adapters` the adapter complains it is not found (perhaps `\config\` structure uses it internally) so I have to pass them locally while initializing `opts.adapters = all_adapters` by invoking load_all_adapterdata/discussions/208.md
Missing cmp with / or @
Date: 2024-08-30
0.10.1
Operating system and version
win 11
Expected behavior
type `/` or `@`, show cmp for select.
The cmp log shows: cmp sources set true, but I don’t see any thing like telescope window pop up
Actual behavior
nothing
Minimal config
_No response_
Steps to reproduce
_No response_
Console logs
_No response_
Date: 2024-08-30
Date: 2024-08-31
the config:
lua
return {
— … your other plugins
{
“olimorris/codecompanion.nvim”,
dependencies = {
“nvim-lua/plenary.nvim”,
“nvim-treesitter/nvim-treesitter”,
“hrsh7th/nvim-cmp”, — Optional: For using slash commands and variables in the chat buffer
“nvim-telescope/telescope.nvim”, — Optional: For using slash commands
{ “stevearc/dressing.nvim”, opts = {} }, — Optional: Improves the default Neovim UI
},
config = function()
local conf = {
strategies = {
chat = {
adapter = “copilot”, — Ensure this is an adapter you have configured
},
inline = {
adapter = “copilot”,
},
agent = {
adapter = “copilot”,
},
},
— NOTE: If you are encountering the ‘missing id’ error,
— you should pass `true` to `cmd_args` for `resolve_args`
adapters = {
— Example for setting a config variable specifically for this project
copilot = function()
return require(“codecompanion.adapters”).extend(“copilot”, {
schema = {
model = {
default = “claude-3.5-sonnet”,
},
max_tokens = {
default = 4096,
},
},
})
end,
openai = function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
name = “my_openai”,
env = {
api_key = “1”,
url = “http://xxx/v1”,
},
schema = {
model = {
default = “gpt-4o-2024-08-06”,
},
},
})
end,
},
display = {
diff = {
provider = “mini_diff”,
},
},
}
local wk = require(“which-key”)
wk.add({
{ “
{ “
})
require(“codecompanion”).setup(conf)
end,
},
}
Date: 2024-08-31
local wk = require(“which-key”)
wk.add({
{ “
{ “
})
require(“codecompanion”).setup({
strategies = {
chat = {
adapter = “copilot”,
},
inline = {
adapter = “copilot”,
},
agent = {
adapter = “copilot”,
},
},
adapters = {
copilot = function()
return require(“codecompanion.adapters”).extend(“copilot”, {
schema = {
model = {
default = “claude-3.5-sonnet”,
},
max_tokens = {
default = 4096,
},
},
})
end,
openai = function()
return require(“codecompanion.adapters”).extend(“openai_compatible”, {
name = “my_openai”,
env = {
api_key = “1”,
url = “http://xxx/v1”,
},
schema = {
model = {
default = “gpt-4o-2024-08-06”,
},
},
})
end,
},
display = {
diff = {
provider = “mini_diff”,
},
},
})
!Screenshot 2024-08-31 at 18 10 39
Date: 2024-09-02
lua
{
“hrsh7th/nvim-cmp”,
dependencies = { “hrsh7th/cmp-emoji” },
—@param opts cmp.ConfigSchema
opts = function(_, opts)
local cmp = require(“cmp”)
opts.sources = cmp.config.sources({
{ name = “nvim_lsp” },
{ name = “path” },
}, {
{ name = “buffer” },
})
— the cmp codecompanion needs this
table.insert(opts.sources, { name = “codecompanion” })
end,
},
Date: 2024-09-02
Will mark this issue as resolved.
data/discussions/21.md
s, this was a great tip to do it like this `diffput`. Is doing PR right away without creating a PR considered rude :joy: ? I can create an issue next time if preferred.
It should have been a “cleaner” solution using `clear_namespace` so it didn’t delete signs created from plugins. I’ve updated my comment to account for that. Let me know what you think of it :)
Date: 2024-03-24
But this PR definitely made the visual experience really nice!
feat: auto-accept suggested inline changes.
Date: 2024-03-09
A hacky solution probably… I’ll try and come up with something better as soon as possible.
!Screen Recording 2024-03-09 at 23 48 57
Date: 2024-03-10
Could we remove the magic numbers and opt for a named parameter instead using `{ on_accept = true }` or something?
Date: 2024-03-10
I did try `diffput` iterating all extmarks to basically `pull` from scratchpad but as soon as we `diffput` one sign no more diff information exists inside the scratchpad buffer.
Also, im considering this an issue as well since calling `:diffput` inside a scratchpad buffer natively removes any remaining “virtual_text”.
For example. Say you have 2 hunks inside of the scratchpad. You accepted the first one using `:diffput`, the first hunk will be replaced just as normal inside `target`. However, `scratch` wouldn’t be “highlighted” red/green on the 2nd hunk anymore thus returning `vim.fn.sign_getplaced` to `[]`.
lua
— codecompanion.utils.diff.lua#L112
— `difffput` removes sign placed (virtual text diff).
if vim.api.nvim_get_current_buf() == scratch and vim.api.nvim_get_current_buf() ~= target then
local buf_signs = vim.fn.sign_getplaced(scratch, { group = “*” })[1].signs
if #buf_signs == 0 then
M.reject(scratch)
end
end
— codecompanion.utils.diff.lua#L89
— Redo virtual text on the previous hunks that we haven’t “put”.
— the logic to “diffput” all ranges/extmarks presented in strategies.diff#hunks can be executed above as well. But this applies after user has put 1 of 2 hunks but the diff gets removed.
…
target_coords = vim.api.nvim_buf_get_extmark_by_id(target, ns_id, data[1], { details = true })
if vim.tbl_isempty(target_coords) then
return
end
scratch_coords[2] = scratch_coords[2] + 1
local removed_lines = vim.api.nvim_buf_get_lines(target, target_coords[1], target_coords[3] + 1, false)
vim.api.nvim_buf_clear_namespace(scratch, ns_id, 0, -1) — To only remove signs from ns_id, this applies only to the `scratch` buffer since target clears its own namespace when diffput occurs. Note that target shouldn’t be touched! (No signs get placed on target).
add_highlights(scratch, target_coords[3] – target_coords[1] + 1, scratch_coords, “red”)
Date: 2024-03-10
he “tools” option. As mentioned `gemini`, `anthropic`, and `openai` schemas support this, so wait, I’m confused now 😅 why `openai` tool configuration is done with `tools`, and gemini with `opts`, considering they are “first citizens” in CodeCompanion’s support list for LLMs adapter, and it doesn’t align out of the box with codecompanion functionality (since tools structure are already baked in).
The workaround relies on a user figuring what parameters Gemini’s API takes and overriding it via its own schema instead of overriding functions in `.adapters` or `handlers.setup`. To make CodeCompanion robust, those adapters should ideally handle `tools` efficiently and gracefully out-of-the-box IMO.
The workaround indeed fixes the tool usage (mostly), but as you said, to bypass `.chat()` limitation of agent tools when sending output back through API request (it generates 400 bad request due agent parameters missing or wrongly parsed internally by codecompanion formatters or adapters for gemini output request via API calls)… what is making the call crash? Can add another parameter to not send tool output to Gemini via `.chat()`. ?
Date: 2024-09-08
> why openai tool configuration is done with tools, and gemini with opts. considering they are “first citizens” in CodeCompanion’s support list for LLMs adapter, and it doesn’t align out of the box with codecompanion functionality (since tools structure are already baked in).
When OpenAI tools hit standard endpoints, they did so from the get go via an Open Source PR (a big feature add!). Since then, Anthropic have implemented tools. And also Gemini. I just added Gemini the other day quite loosely by using their prompt schema for sending payloads. By CodeCompanion standardising on the `tools:` key, hopefully we bypass this fragmentation.
It crashes because Google have implemented tool requests in a truly bizarre manner (see my link to `call_function_payload`). OpenAI and Anthropic are sensible. Google’s tool response mechanism requires matching the user prompt, then the model’s call_function, then saving that id, returning an object from the user that contains that id, the tool name AND they payload. Just a headache on top of CodeCompanion’s message payload parsing:
lua
— Current user and function response model
{
role = “user”
content = “what is the diff to the editor tool”,
},
{
role = “model”, — Wait, Gemini only accepts role = `model` ?? I’m sure I added a parser. Either way `assistant` throws an error on API calls because it only accepts “model” “user”
content = “”,
tool_calls = {
name = “editor”
arguments = {
— …
}
}
},
{
role = “user”,
content = ‘some status from tool’
}
—
They also only allow an alternating user <> model format so any user <> user formatting will be promptly rejected..which commonly happens with standard tools! As per https://ai.google.dev/gemini-api/docs/function-calling/tutorial?lang=rest#function-response
Date: 2024-09-08
Wait since it only accepts alternating calls `user <> model `, how about changing `user -> model` manually on the parsing method to alternate after reaching an un-balanced count.
Like grouping user tags if
lua
while current is user… and count_current_role is % 2 != 0 do
append_to_latest_user
If model != % 2 != 0 then — It means it’s unblanced and waiting for a model response!
insert_model(say it generated nothing or give it space.. ” “)
count_model += 1
Just as an idea. Maybe not implement it since we don’t have to break our heads over these. Honestly API limitations limit LLM behavior way to much.
I’m currently playing locally with
`gemini-1.5-pro-exp-0827_GGUF`, it uses almost all standard agents with 90% completion rate out of the box via agent chat format (XML payload) because standard parsing doesn’t have the “model” requirement limitations. Using standard agent protocol has to be arguably one of the greatest features I’ve tested compared to Copilot and all the current major editors—just as long as standard parsing logic maintains simplicity, or doesn’t forcefully impose API limitation routing when executing standard agents like `editor`.
Thank you for everything man!
Date: 2024-09-08
It’s actually why I’ll keep the legacy tool implementations for weak/open source models and make all of the major models fall in-line with standard APIs by default. The problem occurs currently (as of reading this, though I think you’ve figured it out), is that the plugin evaluates whether standard LLM API tools are available _before_ checking and reverting to standard XML inputs in the chat stream!
There shouldn’t be much structural work required; we can just lean on the `formatters`, which are designed precisely for this kind of behavior. They receive standard inputs from the core adapter framework via their base definitions and then parse everything cleanly out into whatever obscure format OpenAI, Anthropic, or in this case, Google, wants at API consumption level!
So Google will just get the standard function payload from one of its adapters formatters!
Glad you’re enjoying and pushing the boundaries!! Appreciate yours and everyones testing over the past few weeks!
Date: 2024-09-09
Feature Request: gemini API tools support in adapter parameters
Date: 2024-09-07
The new API system allows `setup.adapters… ` options block out tools out of the box. Meaning users don’t have to define tools via `adapter(handlers.setup)` anymore! But unfortunately `gemini` seems to be completely missing out on this?
lua
— Adding dynamic properties for Gemini Tools Support over tools parameter
local geminiCustomToolSupportedAdapter = function()
return require(“codecompanion.adapters”).extend(“gemini”, {
env = {
api_key = “…”,
},
schema = {
model = {
default = “gemini-1.5-pro-exp-0827”
},
},
})
end
Wait let me test if `gemini` actually takes tools by default on the api
lua
gemini = function()
return require(“codecompanion.adapters”).extend(“gemini”, {
name=”my_gemini_with_tools”
env = {
api_key = “cmd:cat ~/.config/nvim/api_keys/gemini.txt”,
chat_url = “http://127.0.0.1:8080/v1/chat/completions” — This is a gemini openai to api wrapper
},
schema = {
model = {
default = “gemini-1.5-pro-exp-0827”
},
},
options = {
[….] — Wait what? No tools available in configuration!
}
})
end
Wait, as the new implementation says. `gemini` uses `opts` instead of tools for specifying tool usage while standardizing other adapters over `tools`.
Is this intentional over Google’s API specific limitations, or shouldn’t we add a handler internally inside code companion settings to translate `tools` to `opts` out of the box dynamically via `formatters/adapters.lua` allowing dynamic and modular integrations, just like codecompanion currently integrates custom internal logic and prompts to avoid further confusion?
This ensures no breaking change when configuring and standardizes CodeCompanion adapter APIs parameters:
lua
gemini = function()
…
opts = {
tools = { — This doesn’t seem supported natively inside the setup.adapters options
inline_tools =false
}
}
})
end
Wait, how does codecompanion resolve this? The workaround seems to directly override tools using `schema` :O
lua
— Workaround to standardizing `tools` option back? Is Gemini not internally implemented to handle this inside CodeCompanion?
local geminiCustomToolSupportedAdapter = function()
return require(“codecompanion.adapters”).extend(“gemini”, {
name = “gemini_pro_exp”,
env = {
api_key = “cmd:cat ~/.config/nvim/api_keys/gemini.txt”,
},
schema = {
model = {
default = “gemini-1.5-pro-exp-0827”
},
tools = { — By manually injecting `tools` inside the `schema` table workaround, rather than the `CodeCompanion` standards
inline_tools = false
}
},
})
end
By setting it in `schema` you bypass CodeCompanion’s handler logic completely, basically acting as arbitrary dictionary parameters for the API without any logic behind since it sends tools manually over using `schema` bypassing CodeCompanion completely.
Date: 2024-09-08
When using tools natively via Gemini’s API, the request gets a 400 Bad Request error. Their tool functionality schema requires some very obscure implementation on CodeCompanion’s part from memory: `call_function_payload` being mapped against original prompts `user` payload – something silly like that compared to OpenAI and Anthropic. I added it but removed it as I didn’t want to break the prompt parser logic and keep parity across APIs where possible!
It’s actually really complex keeping parity across Claude, OpenAI and Google 😅
Regardless…
You say that
> It bypasses CodeCompanion completely, acting as arbitrary dictionary parameters
Where precisely are you finding `tools` nested under `opts`? Under CodeCompanion, any key in `schema` is mapped over to dynamically populate the settings interface `({ show_options = true)` inside a chat session. This allows for values natively defined as `
Date: 2024-09-08
You must be right in saying it is incredibly tricky balancing Claude, OpenAI, and Google formats without breaking CodeCompanion’s neat internal parsing architecture across the board!
In the `README.md` and configuration docs, you state OpenAI tools can be enabled via tdata/discussions/24.md
Question: Setup a proxy ?
Date: 2024-03-05
Will `codecompanion` use this proxy in the background curl query? or something we need to do in setting up?
Date: 2024-03-05
If you specifically need to pass variables into curl proxy (e.g. `http://proxy.yournetwork.com:8080`) you can do so per adapter e.g:
lua
require(“codecompanion”).setup({
adapters = {
copilot = function()
return require(“codecompanion.adapters”).extend(“copilot”, {
env = {
proxy = “http://proxy.yournetwork.com:8080”
}
})
end,
},
})
Date: 2024-03-06
For users behind Great Firewall in China, proxy runs typically runs in “http://127.0.0.1:xxxx”, and openAPI does not allow users from CN thus we need proxy either way, locally or globally. CodeCompanion is great to offer this level of customization!
which specifies the



since updating NeoVim I got the following warning when closing the chat buf via `q` inside the buffer:
`Vim:E5560: `vim.schedule_wrap` / `vim.defer_fn` must not be used to bypass `textlock`.`
NeoVim v0.11.0-dev
Steps to reproduce:CodeCompanionChat Toggle` (opens right)
* Make sure `opts.display.chat.window.layout = ‘float’` is not configured
* `
* Ask smth. -> Responds
* Just press `q` in the chat window. Note: The behavior changes! The buffer doesn’t close but creates a split (buffer 2 above, buffer n below) with nothing inside and stays open at buffer 2! Or no new buffer is created, just an empty space where the chat was… Or it simply prints the error message inside `– messages –` with `E5560…`
I checked the codebase:
lua
— lua/codecompanion/strategies/chat.lua
— line 125
vim.api.nvim_buf_set_keymap(M.bufn, “n”, “q”, “”, {
desc = “Close the chat”,
callback = function()
M:close()
end,
})
— line 178 M.close = function(M)
— …
— Close the window or the buffer
if is_floating then
…
else
vim.cmd(“hide”)
end
The error comes from calling `M.is_open` inside `vim.defer_fn` when the chat buffer is closed by running `M:close()` via `vim.cmd(“hide”)`. But I dont know what exact logic inside `M.is_open` causes the event. Is there anyway to prevent `vim.defer_fn` in neoVim recently?
Workaround solution:
Set `hide ` statically instead of the ``.hide” , {
lua
vim.api.nvim_buf_set_keymap(M.bufn, “n”, “q”, “
desc = “Close the chat”,
— …
})
— AND Set M:close to listen to WinClosed event
…
vim.api.nvim_create_autocmd(“WinClosed”, {
buffer = M.bufn,
callback = function()
if not vim.api.nvim_buf_is_valid(M.bufn) then
return
end
— cleanup logic
vim.defer_fn(function()
if not M:is_open() then
clear_chat_buf()
end
end, 0)
end,
})
Maybe this issue belongs to NeoVim Nightly bugs? I’ve seen some older plugins which where broken with a similar error message.
Greetings