Skip to content

Commit 3e7a8a8

Browse files
Danilo Verde RibeiroDanilo Verde Ribeiro
authored andcommitted
Merge branch 'style-assistant-name-is-agent-name'
2 parents 2b691a6 + be7c6a6 commit 3e7a8a8

4 files changed

Lines changed: 331 additions & 87 deletions

File tree

lua/opencode/context.lua

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,16 @@ function M.format_message(prompt, opts)
11791179

11801180
local parts = { { type = 'text', text = prompt } }
11811181

1182+
-- recent_buffers synthetic context
1183+
if config.context and config.context.recent_buffers and config.context.recent_buffers.enabled then
1184+
local ok, recent = pcall(M.get_recent_buffers, prompt, config.context.recent_buffers)
1185+
if ok and recent and #recent > 0 then
1186+
for _, rb in ipairs(recent) do
1187+
table.insert(parts, rb)
1188+
end
1189+
end
1190+
end
1191+
11821192
for _, path in ipairs(context.mentioned_files or {}) do
11831193
table.insert(parts, format_file_part(path, prompt))
11841194
end
@@ -1368,4 +1378,162 @@ function M.extract_legacy_tag(tag, text)
13681378
return nil
13691379
end
13701380

1381+
---@param buf number
1382+
---@return boolean
1383+
local function is_valid_buffer(buf)
1384+
if not vim.api.nvim_buf_is_valid(buf) then
1385+
return false
1386+
end
1387+
if vim.bo[buf].buftype ~= '' then
1388+
return false
1389+
end
1390+
if not vim.bo[buf].modifiable then
1391+
return false
1392+
end
1393+
return true
1394+
end
1395+
1396+
---@param client table
1397+
local function client_supports_symbols(client)
1398+
if not client or not client.server_capabilities then
1399+
return false
1400+
end
1401+
local caps = client.server_capabilities
1402+
return caps.documentSymbolProvider == true or (type(caps.documentSymbolProvider) == 'table')
1403+
end
1404+
1405+
---@param bufnr number
1406+
---@return table[]|nil
1407+
local function fetch_document_symbols(bufnr)
1408+
local params = { textDocument = vim.lsp.util.make_text_document_params(bufnr) }
1409+
local results = {}
1410+
local clients = vim.lsp.get_active_clients({ bufnr = bufnr })
1411+
local any = false
1412+
for _, client in ipairs(clients) do
1413+
if client_supports_symbols(client) then
1414+
any = true
1415+
local ok, resp = pcall(function()
1416+
return client.request_sync('textDocument/documentSymbol', params, 500, bufnr)
1417+
end)
1418+
if ok and resp and resp.result then
1419+
if vim.tbl_islist(resp.result) then
1420+
vim.list_extend(results, resp.result)
1421+
else
1422+
table.insert(results, resp.result)
1423+
end
1424+
end
1425+
end
1426+
end
1427+
if not any or #results == 0 then
1428+
return nil
1429+
end
1430+
return results
1431+
end
1432+
1433+
local function flatten_symbols(symbols, acc, parent)
1434+
acc = acc or {}
1435+
if not symbols then
1436+
return acc
1437+
end
1438+
for _, s in ipairs(symbols) do
1439+
local name = s.name or '<anonymous>'
1440+
local kind = s.kind or 0
1441+
table.insert(acc, { name = name, kind = kind, parent = parent })
1442+
if s.children then
1443+
flatten_symbols(s.children, acc, name)
1444+
end
1445+
end
1446+
return acc
1447+
end
1448+
1449+
---@param prompt string
1450+
---@param opts { enabled: boolean, symbols_only: boolean, max: number }
1451+
---@return OpencodeMessagePart[]|nil
1452+
function M.get_recent_buffers(prompt, opts)
1453+
if not opts or not opts.enabled then
1454+
return nil
1455+
end
1456+
1457+
local bufs = vim.api.nvim_list_bufs()
1458+
local recent = {}
1459+
1460+
-- Collect candidate buffers (MRU ordering approximation by number)
1461+
for _, b in ipairs(bufs) do
1462+
if is_valid_buffer(b) then
1463+
local line_count = vim.api.nvim_buf_line_count(b)
1464+
if line_count > 100 then
1465+
local clients = vim.lsp.get_active_clients({ bufnr = b })
1466+
if #clients > 0 then
1467+
table.insert(recent, { bufnr = b, line_count = line_count })
1468+
end
1469+
end
1470+
end
1471+
end
1472+
1473+
if #recent == 0 then
1474+
return nil
1475+
end
1476+
1477+
table.sort(recent, function(a, b)
1478+
return a.bufnr > b.bufnr -- crude MRU heuristic
1479+
end)
1480+
1481+
local max_items = math.max(1, opts.max or 5)
1482+
local parts = {}
1483+
for i = 1, math.min(#recent, max_items) do
1484+
local b = recent[i].bufnr
1485+
local path = vim.api.nvim_buf_get_name(b)
1486+
local rel_path = vim.fn.fnamemodify(path, ':~:.')
1487+
local mention = '@' .. rel_path
1488+
local pos = prompt and prompt:find(mention)
1489+
pos = pos and pos - 1 or 0
1490+
1491+
local symbol_list
1492+
if opts.symbols_only then
1493+
local symbols = fetch_document_symbols(b)
1494+
if symbols then
1495+
local flat = flatten_symbols(symbols)
1496+
local names = {}
1497+
for _, s in ipairs(flat) do
1498+
table.insert(names, s.name)
1499+
end
1500+
symbol_list = names
1501+
end
1502+
-- Guarantee a symbols array exists (empty if none found) for a stable contract
1503+
if not symbol_list then
1504+
symbol_list = {}
1505+
end
1506+
end
1507+
1508+
local content
1509+
if not opts.symbols_only then
1510+
local first_lines = vim.api.nvim_buf_get_lines(b, 0, math.min(200, vim.api.nvim_buf_line_count(b)), false)
1511+
content = table.concat(first_lines, '\n')
1512+
end
1513+
1514+
local data = {
1515+
context_type = 'recent-buffer',
1516+
path = path,
1517+
relative = rel_path,
1518+
line_count = recent[i].line_count,
1519+
symbols = symbol_list,
1520+
preview = content and ('```\n' .. content .. '\n```') or nil,
1521+
}
1522+
1523+
local part = {
1524+
type = 'text',
1525+
text = vim.json.encode(data),
1526+
synthetic = true,
1527+
source = {
1528+
path = path,
1529+
type = 'file',
1530+
text = { start = pos, value = mention, ['end'] = pos + #mention - 1 },
1531+
},
1532+
}
1533+
table.insert(parts, part)
1534+
end
1535+
1536+
return parts
1537+
end
1538+
13711539
return M

lua/opencode/types.lua

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@
267267
---@field msg_idx number|nil Message index in session
268268
---@field part_idx number|nil Part index in message
269269
---@field role 'user'|'assistant'|'system'|nil Message role
270-
---@field type 'text'|'tool'|'header'|nil Message part type
270+
---@field type 'text'|'tool'|'header'|'patch'|'step-start'|nil Message part type
271271
---@field snapshot? string|nil snapshot commit hash
272272

273273
---@class OutputAction
@@ -278,7 +278,7 @@
278278
---@field display_line number Line number to display the action
279279
---@field range? { from: number, to: number } Optional range for the action
280280

281-
---@alias OutputExtmark vim.api.keyset.set_extmark
281+
---@alias OutputExtmark vim.api.keyset.set_extmark|fun():vim.api.keyset.set_extmark
282282

283283
---@class Message
284284
---@field id string Unique message identifier
@@ -293,6 +293,8 @@
293293
---@field providerID string Provider identifier
294294
---@field role 'user'|'assistant'|'system' Role of the message sender
295295
---@field system_role string|nil Role defined in system messages
296+
---@field mode string|nil Agent/mode used to create this message (from CLI)
297+
---@field assistant_mode string|nil Assistant mode active when message was created (deprecated)
296298
---@field error table
297299

298300
---@class RestorePoint

0 commit comments

Comments
 (0)