first commit

This commit is contained in:
2026-08-14 23:41:57 +08:00
commit 086803a8dd
471 changed files with 91938 additions and 0 deletions
+118
View File
@@ -0,0 +1,118 @@
// This file defines the provider streaming abstraction (US-003/US-007 base):
// the StreamFn contract, the per-delta AssistantMessageEvent set, and the
// AssistantMessageEventStream (a specialization of EventStream) that a provider
// pushes deltas onto while yielding a final AssistantMessage.
//
// Contract (FR-13): a StreamFn never expresses a request failure by returning
// an error. Runtime failures are encoded as an error event plus a terminal
// assistant message (stopReason=error/aborted + errorMessage). The returned
// error is reserved for the earliest "could not even build the stream" case.
package provider
import (
"context"
"github.com/smallnest/pigo/internal/agentcore"
)
// AssistantMessageEvent is the sealed interface for provider stream deltas. The
// loop dispatches on EventKind; the raw event is also surfaced to consumers via
// MessageUpdateEvent.AssistantMessageEvent.
type AssistantMessageEvent interface {
isAssistantMessageEvent()
// EventKind returns the delta discriminant.
EventKind() string
}
// AssistantMessageEvent kinds.
const (
StreamEventStart = "start"
StreamEventText = "text"
StreamEventThinking = "thinking"
StreamEventToolCall = "toolcall"
StreamEventDone = "done"
StreamEventError = "error"
)
// StreamStartEvent carries the initial (usually empty) partial message.
type StreamStartEvent struct{ Partial agentcore.AssistantMessage }
// StreamTextEvent carries the partial message after a text delta.
type StreamTextEvent struct{ Partial agentcore.AssistantMessage }
// StreamThinkingEvent carries the partial after a thinking delta.
type StreamThinkingEvent struct{ Partial agentcore.AssistantMessage }
// StreamToolCallEvent carries the partial after a tool-call delta.
type StreamToolCallEvent struct{ Partial agentcore.AssistantMessage }
// StreamDoneEvent is the terminal success event; Message is the final response.
type StreamDoneEvent struct{ Message agentcore.AssistantMessage }
// StreamErrorEvent is the terminal failure event; Message carries the terminal
// assistant message (stopReason=error/aborted + errorMessage).
type StreamErrorEvent struct {
Message agentcore.AssistantMessage
Err error
}
func (StreamStartEvent) isAssistantMessageEvent() {}
func (StreamTextEvent) isAssistantMessageEvent() {}
func (StreamThinkingEvent) isAssistantMessageEvent() {}
func (StreamToolCallEvent) isAssistantMessageEvent() {}
func (StreamDoneEvent) isAssistantMessageEvent() {}
func (StreamErrorEvent) isAssistantMessageEvent() {}
func (StreamStartEvent) EventKind() string { return StreamEventStart }
func (StreamTextEvent) EventKind() string { return StreamEventText }
func (StreamThinkingEvent) EventKind() string { return StreamEventThinking }
func (StreamToolCallEvent) EventKind() string { return StreamEventToolCall }
func (StreamDoneEvent) EventKind() string { return StreamEventDone }
func (StreamErrorEvent) EventKind() string { return StreamEventError }
// AssistantMessageEventStream is the provider-level stream: deltas of type
// AssistantMessageEvent with a final AssistantMessage result. isComplete fires
// on done/error; extractResult takes the terminal event's message.
type AssistantMessageEventStream = agentcore.EventStream[AssistantMessageEvent, agentcore.AssistantMessage]
// NewAssistantMessageEventStream builds a provider stream wired with the
// done/error completion callbacks.
func NewAssistantMessageEventStream(buffer int) *AssistantMessageEventStream {
s := agentcore.NewEventStream[AssistantMessageEvent, agentcore.AssistantMessage](buffer)
s.IsComplete = func(e AssistantMessageEvent) bool {
k := e.EventKind()
return k == StreamEventDone || k == StreamEventError
}
s.ExtractResult = func(e AssistantMessageEvent) agentcore.AssistantMessage {
switch ev := e.(type) {
case StreamDoneEvent:
return ev.Message
case StreamErrorEvent:
return ev.Message
default:
return agentcore.AssistantMessage{}
}
}
return s
}
// LlmContext is the shaped request handed to a StreamFn: the system prompt, the
// LLM-bound messages (UI-only messages already filtered), and the tools.
type LlmContext struct {
SystemPrompt string
Messages agentcore.MessageList
Tools []agentcore.AgentTool
}
// StreamConfig carries per-request settings for a StreamFn.
type StreamConfig struct {
APIKey string
ThinkingLevel agentcore.ThinkingLevel
// Extra holds provider-specific options; opaque to the loop.
Extra map[string]any
}
// StreamFn produces a provider stream for a model + shaped context. Per the
// contract it returns an error only for early "cannot build the stream"
// failures; all runtime failures ride the returned stream as error events.
type StreamFn func(ctx context.Context, model string, llm LlmContext, cfg StreamConfig) (*AssistantMessageEventStream, error)