Skip to content

Commit 7336e59

Browse files
authored
fix: follow up on the crete-session hook PR (#206)
1 parent 649c860 commit 7336e59

5 files changed

Lines changed: 154 additions & 14 deletions

File tree

.editorconfig

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ end_of_line = lf
1313
[*.md]
1414
trim_trailing_whitespace = false
1515

16+
# insert_final_newline is safe for file types prettier does not format
1617
[*.lua]
1718
indent_size = 4
1819
insert_final_newline = true
1920

21+
[*.txt]
22+
insert_final_newline = true
23+
2024
[Makefile]
21-
indent_style = tab
25+
indent_style = tab
26+
insert_final_newline = true

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,16 +839,25 @@ integrating with other plugins.
839839
--- @type agentic.PartialUserConfig
840840
opts = {
841841
hooks = {
842-
-- Called when a new ACP session is created (or fails to create)
842+
-- Called when a new ACP session is created (or fails to create).
843+
-- Fires on both success and failure; check `data.err` first.
843844
on_create_session_response = function(data)
844845
-- data.session_id: string|nil - The ACP session ID (nil if err is set)
845846
-- data.tab_page_id: number - The Neovim tabpage ID
846-
-- data.response: table|nil - The ACP session creation response (nil if err is set)
847+
-- data.response: table|nil - The ACP session creation response
848+
-- (nil if err is set)
847849
-- data.err: table|nil - Error details if session creation failed
848-
if data.response then
849-
vim.notify("New session: " .. data.response.sessionId)
850+
if data.err then
851+
vim.notify(
852+
"Session failed: " .. vim.inspect(data.err),
853+
vim.log.levels.ERROR
854+
)
855+
return
850856
end
857+
vim.notify("New session: " .. data.response.sessionId)
851858

859+
-- Reset the agentic_usage tabpage var (set by the on_session_update
860+
-- example below) so a new session starts with a clean usage counter.
852861
if vim.api.nvim_tabpage_is_valid(data.tab_page_id) then
853862
vim.t[data.tab_page_id].agentic_usage = nil
854863
end

doc/agentic.txt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -602,10 +602,12 @@ Event hooks ~
602602
opts = {
603603
hooks = {
604604
on_create_session_response = function(data)
605-
-- data.response: table|nil - The ACP session creation response (nil if err is set)
606-
-- data.err: table|nil - Error details if session creation failed
607-
-- data.session_id: string
608-
-- data.tab_page_id: number
605+
-- Fires on both success and failure. Check `data.err` first.
606+
-- data.session_id: string|nil (nil if err is set)
607+
-- data.tab_page_id: number (may be invalid if tab was closed;
608+
-- guard with vim.api.nvim_tabpage_is_valid before use)
609+
-- data.response: table|nil (nil if err is set)
610+
-- data.err: table|nil (nil on success)
609611
end,
610612
on_prompt_submit = function(data)
611613
-- data.prompt: string
@@ -940,4 +942,4 @@ Persistent ACP message log:
940942
`~/.cache/nvim/agentic_debug.log`
941943

942944
==============================================================================
943-
vim:tw=78:ts=8:ft=help:norl:
945+
vim:tw=78:ts=8:ft=help:norl:

lua/agentic/config_default.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525

2626
--- Data passed to the on_create_session_response hook
2727
--- @class agentic.UserConfig.CreateSessionResponseData
28-
--- @field session_id string|nil
29-
--- @field tab_page_id number
30-
--- @field response agentic.acp.SessionCreationResponse|nil
31-
--- @field err? agentic.acp.ACPError
28+
--- @field session_id? string Convenience field; equals response.sessionId when response is non-nil, nil if creation failed
29+
--- @field tab_page_id number The tabpage ID for this session
30+
--- @field response? agentic.acp.SessionCreationResponse Raw ACP create-session response, nil on error
31+
--- @field err? agentic.acp.ACPError Error details if session creation failed
3232

3333
--- Data passed to the on_prompt_submit hook
3434
--- @class agentic.UserConfig.PromptSubmitData

lua/agentic/session_manager.test.lua

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1238,4 +1238,128 @@ describe("agentic.SessionManager", function()
12381238
assert.spy(write_message_spy).was.called(0)
12391239
end)
12401240
end)
1241+
1242+
describe("new_session: on_create_session_response hook", function()
1243+
local Config = require("agentic.config")
1244+
--- @type TestStub
1245+
local schedule_stub
1246+
1247+
before_each(function()
1248+
schedule_stub = spy.stub(vim, "schedule")
1249+
schedule_stub:invokes(function(fn)
1250+
fn()
1251+
end)
1252+
end)
1253+
1254+
--- Build a session mock with just enough surface for the error path.
1255+
--- new_session calls self:_cancel_session and self:_build_handlers
1256+
--- before agent:create_session. Both are stubbed to no-ops so the
1257+
--- test focuses on the hook invocation. The error path returns
1258+
--- immediately after the hook, so success-path collaborators are
1259+
--- not needed.
1260+
--- @return agentic.SessionManager
1261+
local function make_session()
1262+
return {
1263+
tab_page_id = 99,
1264+
session_id = nil,
1265+
status_animation = {
1266+
start = function() end,
1267+
stop = function() end,
1268+
},
1269+
_cancel_session = function() end,
1270+
_build_handlers = function()
1271+
return {}
1272+
end,
1273+
new_session = SessionManager.new_session,
1274+
agent = {
1275+
provider_config = { name = "Test" },
1276+
},
1277+
} --[[@as agentic.SessionManager]]
1278+
end
1279+
1280+
--- Stub agent:create_session to fire its callback synchronously
1281+
--- with the given response/err pair.
1282+
--- @param session agentic.SessionManager
1283+
--- @param response agentic.acp.SessionCreationResponse|nil
1284+
--- @param err agentic.acp.ACPError|nil
1285+
local function fake_create_session(session, response, err)
1286+
session.agent.create_session = function(_self, _handlers, callback)
1287+
callback(response, err)
1288+
end
1289+
end
1290+
1291+
after_each(function()
1292+
schedule_stub:revert()
1293+
Config.hooks = Config.hooks or {}
1294+
Config.hooks.on_create_session_response = nil
1295+
end)
1296+
1297+
it("fires on error with err set and response nil", function()
1298+
local hook_spy = spy.new(function() end)
1299+
Config.hooks = Config.hooks or {}
1300+
Config.hooks.on_create_session_response = function(data)
1301+
hook_spy(data)
1302+
end
1303+
1304+
local session = make_session()
1305+
local err = { code = -32000, message = "boom" }
1306+
fake_create_session(
1307+
session,
1308+
nil,
1309+
err --[[@as agentic.acp.ACPError]]
1310+
)
1311+
1312+
SessionManager.new_session(session)
1313+
1314+
assert.spy(hook_spy).was.called(1)
1315+
local data = hook_spy.calls[1][1]
1316+
assert.is_nil(data.session_id)
1317+
assert.equal(99, data.tab_page_id)
1318+
assert.is_nil(data.response)
1319+
assert.equal(err, data.err)
1320+
assert.is_nil(session.session_id)
1321+
end)
1322+
1323+
it("does not fire when no hook is configured", function()
1324+
Config.hooks = Config.hooks or {}
1325+
Config.hooks.on_create_session_response = nil
1326+
1327+
local session = make_session()
1328+
fake_create_session(session, nil, {
1329+
code = -32000,
1330+
message = "boom",
1331+
} --[[@as agentic.acp.ACPError]])
1332+
1333+
assert.has_no_errors(function()
1334+
SessionManager.new_session(session)
1335+
end)
1336+
end)
1337+
1338+
it("fires before the early return on error", function()
1339+
-- Verifies the contract: hook receives err, then session_id is
1340+
-- cleared. If the hook fired AFTER the early return, it would
1341+
-- never run on the error path.
1342+
local hook_call_order = {}
1343+
Config.hooks = Config.hooks or {}
1344+
Config.hooks.on_create_session_response = function(data)
1345+
table.insert(hook_call_order, {
1346+
err = data.err,
1347+
session_id_at_fire = data.session_id,
1348+
})
1349+
end
1350+
1351+
local session = make_session()
1352+
session.session_id = "stale-id"
1353+
fake_create_session(session, nil, {
1354+
code = -32000,
1355+
message = "boom",
1356+
} --[[@as agentic.acp.ACPError]])
1357+
1358+
SessionManager.new_session(session)
1359+
1360+
assert.equal(1, #hook_call_order)
1361+
assert.is_not_nil(hook_call_order[1].err)
1362+
assert.is_nil(session.session_id)
1363+
end)
1364+
end)
12411365
end)

0 commit comments

Comments
 (0)