Serialize tool deltas through runtime events

Why: wrapper-side tool deltas raced with serialized run events and could disappear under load.

Evidence: TestToolCallDeltaBeforeExecution race reproduced on the old path, then passed ten race runs with Agent-Native e86e74b; full Backend vet and tests pass.

Impact: one owner emits conversation events; Backend pins the Agent-Native event identity contract.

Refs: Agent-Native PR #46; internal/runtime/llm_direct.go
This commit is contained in:
2026-10-14 02:24:26 +00:00
parent 5f834544b0
commit 4363a29653
2 changed files with 5 additions and 6 deletions
+4 -5
View File
@@ -233,9 +233,6 @@ func (l *LLMRunner) runDirect(rc RunCtx, stream agentllm.StreamFunc, model strin
go func() {
defer close(out)
for ev := range in {
if ev.Kind == agentllm.KindToolCallDelta {
st.noteToolDelta(ev)
}
if ev.Kind == agentllm.KindMessageEnd {
if ev.Message.Role == "" {
ev.Message.Role = agentllm.RoleAssistant
@@ -488,13 +485,13 @@ func (st *directRun) noteModelSwitch(from, to string) {
st.switches = append(st.switches, fmt.Sprintf("模型 %s 在输出前失败,已改用 %s", from, to))
}
func (st *directRun) noteToolDelta(ev agentllm.Event) {
func (st *directRun) noteToolDelta(ev nruntime.Event) {
if !st.acting {
_ = st.rc.Emit(core.EvRunPhase, core.RunPhasePayload{Phase: core.PhaseActing})
st.acting = true
}
_ = st.rc.Emit(core.EvToolCallDelta, core.ToolCallDeltaPayload{
Index: ev.ToolIndex, CallID: ev.ToolID, Name: ev.ToolName, Delta: ev.ArgumentsDelta,
Index: ev.ToolIndex, CallID: ev.CallID, Name: ev.Tool, Delta: ev.Detail,
})
}
@@ -511,6 +508,8 @@ func (st *directRun) onEvent(ev nruntime.Event) {
st.thinkStart, st.thinkEnd = time.Time{}, time.Time{}
st.textStart, st.textEnd = time.Time{}, time.Time{}
st.turnBody = ""
case "tool_call_delta":
st.noteToolDelta(ev)
case "text_delta":
if !st.responding {
_ = st.rc.Emit(core.EvRunPhase, core.RunPhasePayload{Phase: core.PhaseResponding})