Files
LocalAI/core/services/agents/events_test.go
Aniruddh Jha 51f4f67c47 fix(agents): emit chat event timestamps in milliseconds (#9867) (#10243)
Agent chat replies rendered a broken timestamp in the web UI
("Invalid Timestamp" / "12:00 AM", identical for every reply) because
the SSE timestamp unit was inconsistent across producers.

EventBridge.PublishEvent emitted Unix nanoseconds while the local
dispatcher (dispatcher.go) already emitted Unix milliseconds, and the
React UI fed the value straight into `new Date(ts)` after dividing by
1e6. Nanoseconds also overflow JS's safe-integer range (~1.7e18).

Standardize on Unix milliseconds: switch PublishEvent to UnixMilli and
drop the /1e6 conversion in AgentChat.jsx so both SSE paths agree and
match the React UI's expectation. Add a regression test asserting the
published timestamp is in milliseconds.
2026-06-12 23:18:44 +02:00

79 lines
2.4 KiB
Go

package agents
import (
"time"
"github.com/mudler/LocalAI/core/services/messaging"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// fakeMessagingClient implements messaging.MessagingClient and captures the
// last published payload so tests can assert on it.
type fakeMessagingClient struct {
lastSubject string
lastData any
}
func (f *fakeMessagingClient) Publish(subject string, data any) error {
f.lastSubject = subject
f.lastData = data
return nil
}
func (f *fakeMessagingClient) Subscribe(string, func([]byte)) (messaging.Subscription, error) {
return &fakeSub{}, nil
}
func (f *fakeMessagingClient) QueueSubscribe(string, string, func([]byte)) (messaging.Subscription, error) {
return &fakeSub{}, nil
}
func (f *fakeMessagingClient) QueueSubscribeReply(string, string, func([]byte, func([]byte))) (messaging.Subscription, error) {
return &fakeSub{}, nil
}
func (f *fakeMessagingClient) SubscribeReply(string, func([]byte, func([]byte))) (messaging.Subscription, error) {
return &fakeSub{}, nil
}
func (f *fakeMessagingClient) Request(string, []byte, time.Duration) ([]byte, error) {
return nil, nil
}
func (f *fakeMessagingClient) IsConnected() bool { return true }
func (f *fakeMessagingClient) Close() {}
type fakeSub struct{}
func (s *fakeSub) Unsubscribe() error { return nil }
var _ = Describe("EventBridge", func() {
Describe("PublishEvent timestamp", func() {
// Regression for #9867: agent chat messages rendered a broken
// timestamp ("Invalid Timestamp" / "12:00 AM") in the web UI because
// this path emitted Unix nanoseconds while the local dispatcher and the
// React UI both expect Unix milliseconds. Nanoseconds also overflow JS's
// safe-integer range. The timestamp must be in milliseconds.
It("emits the timestamp in Unix milliseconds", func() {
fake := &fakeMessagingClient{}
bridge := NewEventBridge(fake, nil, "instance-1")
before := time.Now().UnixMilli()
err := bridge.PublishMessage("agent", "user", "agent", "hello", "msg-1")
after := time.Now().UnixMilli()
Expect(err).ToNot(HaveOccurred())
evt, ok := fake.lastData.(AgentEvent)
Expect(ok).To(BeTrue(), "published payload should be an AgentEvent")
// A millisecond timestamp falls within [before, after]; a nanosecond
// one (~1e6 larger) would be far outside this window.
Expect(evt.Timestamp).To(BeNumerically(">=", before))
Expect(evt.Timestamp).To(BeNumerically("<=", after))
})
})
})