Skip to content

Conversation

flc1125
Copy link
Member

@flc1125 flc1125 commented May 25, 2025

feat(eino/callbacks/otel): implement OnEndWithStreamOutput method

Summary

Completes the implementation of the OpenTelemetry handler for eino callbacks by implementing the previously stubbed OnEndWithStreamOutput method. This method handles the end of component execution when the output is a stream rather than a regular value.

Key changes:

  • Implemented OnEndWithStreamOutput in eino/callbacks/otel/handler.go following the existing OnEnd pattern
  • Fixed CI lint failure by cleaning up coverage files and committing go.sum dependency updates
  • All CI checks now pass

The implementation follows the same span lifecycle management as the existing OnEnd method: validates input parameters, retrieves OpenTelemetry state from context, checks span validity, and ensures proper span cleanup via defer.

Review & Testing Checklist for Human

⚠️ Important: This implementation needs careful review as stream handling has specific requirements that may differ from regular output handling.

  • Verify stream output handling is correct - The implementation currently ignores the output *schema.StreamReader[callbacks.CallbackOutput] parameter entirely. Review if this is the intended behavior or if stream-specific processing is needed.
  • Test with actual stream scenarios - Create a test case that exercises this method with real stream output to ensure it works correctly in practice and doesn't break stream consumption.
  • Compare with OnEnd behavior - The OnEnd method processes its output parameter, but this implementation doesn't touch the stream. Verify if this behavioral difference is intentional.
  • Check interface compliance - Confirm this implementation fully satisfies the callbacks.Handler interface requirements and matches expected usage patterns in the eino ecosystem.

Recommended test plan:

  1. Run eino components that produce stream output with this handler enabled
  2. Verify spans are created and ended correctly for streaming scenarios
  3. Check that stream consumption still works after handler processing
  4. Validate OpenTelemetry traces contain expected span information

Diagram

%%{ init : { "theme" : "default" }}%%
graph TD
    CallbacksHandler["callbacks.Handler<br/>(interface)"]:::context
    OtelHandler["eino/callbacks/otel/<br/>handler.go"]:::major-edit
    OnEnd["OnEnd()<br/>(existing method)"]:::context  
    OnEndStream["OnEndWithStreamOutput()<br/>(new implementation)"]:::major-edit
    OtelState["eino/callbacks/otel/<br/>state.go"]:::context
    GoSum["eino/callbacks/otel/<br/>go.sum"]:::minor-edit
    
    CallbacksHandler --> OtelHandler
    OtelHandler --> OnEnd
    OtelHandler --> OnEndStream
    OtelHandler --> OtelState
    OtelHandler --> GoSum
    
    OnEnd -.->|"pattern followed"| OnEndStream
    OtelState -->|"span management"| OnEndStream
    
    subgraph Legend
        L1[Major Edit]:::major-edit
        L2[Minor Edit]:::minor-edit  
        L3[Context/No Edit]:::context
    end
    
    classDef major-edit fill:#90EE90
    classDef minor-edit fill:#87CEEB  
    classDef context fill:#FFFFFF
Loading

Notes

  • Session info: Implemented by @flc1125, session: https://app.devin.ai/sessions/1a2a7189637f4f2097a68720fa46b1f0
  • CI status: All 11 checks passing including the previously failing lint check
  • Risk level: Medium - The core implementation follows established patterns, but stream-specific behavior needs validation
  • Missing: Tests for the new method and verification of stream output handling requirements

- Implement an OpenTelemetry handler for eino callbacks
- Add options to configure the handler, including custom tracer provider
- Implement context propagation for OpenTelemetry spans
- Update statshandler_test.go to use lowercase 'span' in comments
Copy link

coderabbitai bot commented May 25, 2025

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

A new otel package is introduced in eino/callbacks, providing OpenTelemetry tracing support for callback executions. The package includes a handler struct, configurable via functional options, that implements the callbacks.Handler interface to manage span lifecycle and annotate traces with callback and model metadata. Utility functions support context management and span enrichment.

Changes

File(s) Change Summary
eino/callbacks/otel/go.mod Added Go module file with dependencies and local replace directive for development.
eino/callbacks/otel/handler.go Introduced Handler struct implementing OpenTelemetry tracing for callback lifecycle events.
eino/callbacks/otel/options.go Added functional options pattern for handler configuration, including tracer provider injection.
eino/callbacks/otel/utils.go Added utilities for context span state management and span enrichment with callback/model metadata.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CallbackExecutor
    participant OTELHandler
    participant OpenTelemetry

    User->>CallbackExecutor: Initiate Callback
    CallbackExecutor->>OTELHandler: OnStart(ctx, info, input)
    OTELHandler->>OpenTelemetry: Start Span
    OTELHandler->>OTELHandler: Annotate Span (run info, input)
    OTELHandler-->>CallbackExecutor: ctx (with span)
    CallbackExecutor->>OTELHandler: OnError(ctx, info, err) / OnEnd(ctx, info, output)
    OTELHandler->>OpenTelemetry: Record error / End Span
Loading

Poem

In the land of traces, a handler hops in,
With context and spans, let observability begin!
Metadata sprinkled, events in a row,
Through OpenTelemetry, our stories now show.
A hop, a span, a callback’s delight—
Tracing with carrots, from morning to night. 🥕✨

✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch eino-callbacks-otel

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

- Changed 'span' to 'Span' in the comment for consistency with the code
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
eino/callbacks/otel/utils.go (1)

25-30: Consider edge cases in span name generation.

The getName function could produce empty or unexpected span names in edge cases:

  • If info.Type is empty, the span name would only be the Component
  • If both info.Type and info.Component are empty, the span name would be empty

Consider adding validation or fallback logic to ensure meaningful span names.

 func getName(info *callbacks.RunInfo) string {
 	if len(info.Name) != 0 {
 		return info.Name
 	}
-	return info.Type + string(info.Component)
+	name := info.Type + string(info.Component)
+	if name == "" {
+		return "unknown"
+	}
+	return name
 }
eino/callbacks/otel/handler.go (1)

40-54: Consider enhancing span observability.

The implementation is solid with proper defensive programming. Consider these optional improvements:

  1. Add span attributes from the callback info for better observability
  2. The span kind is hardcoded to SpanKindInternal - consider making it configurable based on the callback type

Example enhancement:

 func (h *Handler) OnStart(ctx context.Context, info *callbacks.RunInfo, input callbacks.CallbackInput) context.Context {
 	if info == nil {
 		return ctx
 	}
 
 	spanName := getName(info)
 
 	ctx, span := h.tracer.Start(ctx, spanName,
 		trace.WithSpanKind(trace.SpanKindInternal),
+		trace.WithAttributes(
+			attribute.String("callback.name", info.Name),
+			attribute.String("callback.type", string(info.Type)),
+		),
 	)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2aad55 and d731f31.

⛔ Files ignored due to path filters (1)
  • eino/callbacks/otel/go.sum is excluded by !**/*.sum
📒 Files selected for processing (5)
  • eino/callbacks/otel/go.mod (1 hunks)
  • eino/callbacks/otel/handler.go (1 hunks)
  • eino/callbacks/otel/options.go (1 hunks)
  • eino/callbacks/otel/utils.go (1 hunks)
  • kratos/middleware/tracing/statshandler_test.go (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
eino/callbacks/otel/options.go (1)
eino/callbacks/otel/handler.go (1)
  • Handler (16-20)
eino/callbacks/otel/utils.go (1)
support/contexts/values.go (1)
  • Value (5-8)
eino/callbacks/otel/handler.go (2)
eino/callbacks/otel/options.go (1)
  • Option (5-7)
version.go (1)
  • Version (3-5)
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: lint
  • GitHub Check: go test (1.24.x, ubuntu-latest, mysql:5.7)
  • GitHub Check: go test (1.23.x, ubuntu-latest, mysql:latest)
  • GitHub Check: go test (1.24.x, ubuntu-latest, mysql:latest)
  • GitHub Check: go test (1.23.x, ubuntu-latest, mysql:5.7)
  • GitHub Check: Analyze (go)
🔇 Additional comments (10)
eino/callbacks/otel/go.mod (1)

3-3:

✅ Verification successful

Verify Go version requirement is not too restrictive.

Go 1.23.0 is quite recent and may cause compatibility issues for users on older Go versions. Consider using a more conservative version requirement unless specific 1.23.0 features are required.


🌐 Web query:

What Go versions are currently supported and widely used? Is Go 1.23.0 requirement too restrictive for a library?

💡 Result:

As of May 25, 2025, the Go programming language supports the following versions:

  • Go 1.24.x: The latest stable release, with the most recent update being Go 1.24.3, released on May 6, 2025. (go.dev)

  • Go 1.23.x: The previous stable release, with the latest update being Go 1.23.9, released on May 6, 2025. (go.dev)

Go 1.22 and earlier versions have reached their end of support. (endoflife.date)

Regarding your question about setting Go 1.23.0 as a requirement for a library: Go 1.23.0 was released on August 13, 2024. (go.dev) By May 2025, Go 1.23.0 is still within its support period, and many developers are likely using it. Therefore, requiring Go 1.23.0 for your library is not overly restrictive and aligns with current usage patterns.

Citations:


Go 1.23.0 requirement is acceptable
As of May 2025, Go 1.23.x is still supported and widely used. Requiring Go 1.23.0 for this library aligns with current usage and is not overly restrictive.

kratos/middleware/tracing/statshandler_test.go (1)

69-69: LGTM: Consistent comment styling.

Good stylistic improvement - using lowercase 'span' in comments is more consistent with Go conventions unless referring to the specific Span type.

eino/callbacks/otel/options.go (1)

5-19: LGTM: Clean functional options implementation.

The functional options pattern is implemented correctly following Go best practices. The Option interface, optionFunc type, and WithTracerProvider function provide a clean and extensible way to configure the Handler.

eino/callbacks/otel/utils.go (1)

10-23: LGTM: Well-implemented context utilities.

The context utilities follow Go best practices:

  • Using an unexported struct type as context key prevents collisions
  • Safe type assertion with boolean return in fromOTelState
  • Clean separation of concerns with the otelState wrapper
eino/callbacks/otel/handler.go (6)

1-12: LGTM!

The package declaration and imports are well-structured and include all necessary dependencies for OpenTelemetry integration.


14-22: LGTM!

The scope name follows OpenTelemetry naming conventions, and the Handler struct design is clean with appropriate interface compliance verification.


24-38: LGTM!

The constructor follows best practices with functional options pattern and properly initializes the tracer with appropriate scope name and instrumentation version.


56-73: LGTM!

The implementation correctly handles span lifecycle with proper defensive checks and uses defer to ensure spans are properly ended.


75-95: LGTM!

The error handling correctly follows OpenTelemetry conventions by recording errors and setting appropriate span status with proper defensive programming.


97-105:

✅ Verification successful

Verify that placeholder implementations are acceptable.

The streaming methods are not implemented and contain TODO comments. Ensure that:

  1. The callbacks.Handler interface allows placeholder implementations
  2. Existing code doesn't rely on these methods being functional
  3. There's a plan to implement these methods if streaming functionality is needed

🏁 Script executed:

#!/bin/bash
# Description: Check if streaming methods are used elsewhere in the codebase
# Expected: Find any usage of OnStartWithStreamInput or OnEndWithStreamOutput

echo "Searching for usage of streaming callback methods..."
rg -A 3 "OnStartWithStreamInput|OnEndWithStreamOutput"

echo "Checking if streaming is mentioned in tests..."
rg -A 5 -B 5 "stream.*callback|callback.*stream" --type go

Length of output: 975


Confirm No-Op Streaming Callbacks

Searches show that neither OnStartWithStreamInput nor OnEndWithStreamOutput are ever invoked (in code or tests), so these stub implementations satisfy the interface without impacting existing functionality. No immediate fixes are required—just ensure there’s a plan (e.g., an issue or roadmap entry) to replace the // TODO implement me stubs when streaming support is added.

flc1125 added 2 commits May 25, 2025 22:15
…ributes

- Add more attributes to the span, including run info and model callback input
- Create separate functions for adding attributes to improve code organization
- Remove redundant context key struct and simplify context handling
- Update naming convention for consistency with OpenTelemetry guidelines
…ributes

- Add more attributes to the span, including run info and model callback input
- Create separate functions for adding attributes to improve code organization
- Remove redundant context key struct and simplify context handling
- Update naming convention for consistency with OpenTelemetry guidelines
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
eino/callbacks/otel/utils.go (1)

22-31: Consider using the existing generic context utility.

The implementation is correct, but you could leverage the existing generic Value function from support/contexts/values.go for better type safety and consistency.

+import "github.com/go-fries/fries/support/contexts"

 // fromOTelState retrieves the OpenTelemetry state from the context.
 func fromOTelState(ctx context.Context) (*otelState, bool) {
-	state, ok := ctx.Value(otelStateKey{}).(*otelState)
-	return state, ok
+	return contexts.Value[*otelState](ctx, otelStateKey{})
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d731f31 and 1f21934.

📒 Files selected for processing (2)
  • eino/callbacks/otel/handler.go (1 hunks)
  • eino/callbacks/otel/utils.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • eino/callbacks/otel/handler.go
🧰 Additional context used
🧬 Code Graph Analysis (1)
eino/callbacks/otel/utils.go (1)
support/contexts/values.go (1)
  • Value (5-8)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: lint
  • GitHub Check: Analyze (go)
🔇 Additional comments (4)
eino/callbacks/otel/utils.go (4)

1-12: LGTM! Clean package structure and appropriate imports.

The package declaration and imports are well-organized and include the necessary OpenTelemetry dependencies for tracing functionality.


14-20: LGTM! Proper context key design pattern.

The otelStateKey struct{} follows Go best practices for context keys, and the otelState struct appropriately encapsulates the trace span.


41-47: LGTM! Consistent attribute naming.

The span annotation follows a clear naming convention with the "eino.runinfo." prefix for all attributes.


33-39:

❓ Verification inconclusive

Verify Component type conversion safety.

The string conversion string(info.Component) assumes Component can be safely converted to string. Please verify this is always valid.


🏁 Script executed:

#!/bin/bash
# Description: Check the type of Component field in callbacks.RunInfo
# Expected: Component should be a type that can be converted to string

ast-grep --pattern 'type RunInfo struct {
  $$$
  Component $_
  $$$
}'

Length of output: 73


🏁 Script executed:

#!/bin/bash
# Locate the RunInfo struct definition and inspect the Component field
rg -n -C3 'type RunInfo struct' --include '*.go'

Length of output: 492


#!/bin/bash
# Search for the RunInfo struct definition in the callbacks package
rg -n -C3 'type RunInfo struct' eino/callbacks

#!/bin/bash
# Search for the RunInfo struct definition and its Component field type
grep -R -n -C3 "type RunInfo struct" eino/callbacks
grep -R -n -C2 "Component" eino/callbacks

Unable to locate RunInfo definition—please verify Component conversion safety

  • We couldn’t find the RunInfo struct (and its Component field) in the local codebase.
  • Confirm that Component is either a string alias or has an underlying type safe for string(info.Component) conversion (e.g. type Component string).
  • If Component is numeric or otherwise non-string, casting produces a Unicode code point. In that case, consider using fmt.Sprint(info.Component) or providing a String() string method on Component.

Comment on lines 49 to 84
func spanWithModelCallbackInput(span trace.Span, input callbacks.CallbackInput) {
callbackInput := model.ConvCallbackInput(input)
if callbackInput == nil {
return
}

if config := callbackInput.Config; config != nil {
span.SetAttributes(
semconv.GenAIRequestModel(config.Model),
semconv.GenAIRequestMaxTokens(config.MaxTokens),
semconv.GenAIRequestTemperature(float64(config.Temperature)),
semconv.GenAIRequestTopP(float64(config.TopP)),
)
}

if len(callbackInput.Messages) > 0 {
for i, msg := range callbackInput.Messages {
span.AddEvent(
fmt.Sprintf("input.message.%d", i+1),
trace.WithAttributes(
attribute.String("gen_ai.request.role", string(msg.Role)),
attribute.String("gen_ai.request.content", msg.Content),
// Add more attributes as needed
),
)
}
}

if extra := callbackInput.Extra; len(extra) > 0 {
attrs := make([]attribute.KeyValue, 0, len(extra))
for k, v := range extra {
attrs = append(attrs, attribute.String("callback.input.extra."+k, fmt.Sprintf("%v", v)))
}
span.SetAttributes(attrs...)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve semantic convention usage and error handling.

Several improvements needed for robustness and standards compliance:

  1. Use semantic convention constants for message attributes
  2. Add nil checks for config fields
  3. Handle potential type conversion errors
 func spanWithModelCallbackInput(span trace.Span, input callbacks.CallbackInput) {
 	callbackInput := model.ConvCallbackInput(input)
 	if callbackInput == nil {
 		return
 	}
 
 	if config := callbackInput.Config; config != nil {
-		span.SetAttributes(
-			semconv.GenAIRequestModel(config.Model),
-			semconv.GenAIRequestMaxTokens(config.MaxTokens),
-			semconv.GenAIRequestTemperature(float64(config.Temperature)),
-			semconv.GenAIRequestTopP(float64(config.TopP)),
-		)
+		attrs := []attribute.KeyValue{}
+		if config.Model != "" {
+			attrs = append(attrs, semconv.GenAIRequestModel(config.Model))
+		}
+		if config.MaxTokens > 0 {
+			attrs = append(attrs, semconv.GenAIRequestMaxTokens(config.MaxTokens))
+		}
+		if config.Temperature != 0 {
+			attrs = append(attrs, semconv.GenAIRequestTemperature(float64(config.Temperature)))
+		}
+		if config.TopP != 0 {
+			attrs = append(attrs, semconv.GenAIRequestTopP(float64(config.TopP)))
+		}
+		if len(attrs) > 0 {
+			span.SetAttributes(attrs...)
+		}
 	}
 
 	if len(callbackInput.Messages) > 0 {
 		for i, msg := range callbackInput.Messages {
 			span.AddEvent(
 				fmt.Sprintf("input.message.%d", i+1),
 				trace.WithAttributes(
-					attribute.String("gen_ai.request.role", string(msg.Role)),
-					attribute.String("gen_ai.request.content", msg.Content),
-					// Add more attributes as needed
+					semconv.GenAIPromptRole(string(msg.Role)),
+					semconv.GenAIPromptContent(msg.Content),
 				),
 			)
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func spanWithModelCallbackInput(span trace.Span, input callbacks.CallbackInput) {
callbackInput := model.ConvCallbackInput(input)
if callbackInput == nil {
return
}
if config := callbackInput.Config; config != nil {
span.SetAttributes(
semconv.GenAIRequestModel(config.Model),
semconv.GenAIRequestMaxTokens(config.MaxTokens),
semconv.GenAIRequestTemperature(float64(config.Temperature)),
semconv.GenAIRequestTopP(float64(config.TopP)),
)
}
if len(callbackInput.Messages) > 0 {
for i, msg := range callbackInput.Messages {
span.AddEvent(
fmt.Sprintf("input.message.%d", i+1),
trace.WithAttributes(
attribute.String("gen_ai.request.role", string(msg.Role)),
attribute.String("gen_ai.request.content", msg.Content),
// Add more attributes as needed
),
)
}
}
if extra := callbackInput.Extra; len(extra) > 0 {
attrs := make([]attribute.KeyValue, 0, len(extra))
for k, v := range extra {
attrs = append(attrs, attribute.String("callback.input.extra."+k, fmt.Sprintf("%v", v)))
}
span.SetAttributes(attrs...)
}
}
func spanWithModelCallbackInput(span trace.Span, input callbacks.CallbackInput) {
callbackInput := model.ConvCallbackInput(input)
if callbackInput == nil {
return
}
if config := callbackInput.Config; config != nil {
attrs := []attribute.KeyValue{}
if config.Model != "" {
attrs = append(attrs, semconv.GenAIRequestModel(config.Model))
}
if config.MaxTokens > 0 {
attrs = append(attrs, semconv.GenAIRequestMaxTokens(config.MaxTokens))
}
if config.Temperature != 0 {
attrs = append(attrs, semconv.GenAIRequestTemperature(float64(config.Temperature)))
}
if config.TopP != 0 {
attrs = append(attrs, semconv.GenAIRequestTopP(float64(config.TopP)))
}
if len(attrs) > 0 {
span.SetAttributes(attrs...)
}
}
if len(callbackInput.Messages) > 0 {
for i, msg := range callbackInput.Messages {
span.AddEvent(
fmt.Sprintf("input.message.%d", i+1),
trace.WithAttributes(
semconv.GenAIPromptRole(string(msg.Role)),
semconv.GenAIPromptContent(msg.Content),
),
)
}
}
if extra := callbackInput.Extra; len(extra) > 0 {
attrs := make([]attribute.KeyValue, 0, len(extra))
for k, v := range extra {
attrs = append(attrs, attribute.String("callback.input.extra."+k, fmt.Sprintf("%v", v)))
}
span.SetAttributes(attrs...)
}
}
🤖 Prompt for AI Agents
In eino/callbacks/otel/utils.go lines 49 to 84, improve semantic convention
usage by replacing hardcoded attribute keys for message roles and content with
appropriate semantic convention constants. Add nil checks for config fields like
Model, MaxTokens, Temperature, and TopP before setting attributes to avoid nil
pointer dereferences. For type conversions such as float64 conversions of
Temperature and TopP, ensure safe handling or validation to prevent runtime
errors. Implement these changes to enhance robustness and standards compliance.

….3.0

- Upgrade github.com/go-fries/fries/v3 from v3.0.0 to v3.3.0 in eino/callbacks/otel
@flc1125 flc1125 marked this pull request as draft June 5, 2025 13:02
flc1125 and others added 9 commits June 5, 2025 22:22
- Update eino version to v0.3.41
- Remove replace directive for github.com/go-fries/fries/v3
- Add testify as a new dependency
- Refactor Handler initialization and error handling
- Rename utils.go to state.go for better naming convention
- Add version.go and version_test.go for version management
…k lifecycle- Add tracing for OnStartWithStreamInput and OnEndWithStreamOutput- Implement span recording for callback input and output

- Refactor state handling to improve trace context management
- Move span attribute setting to separate functions for better organization
- Update go.opentelemetry.io/otel from v1.36.0 to v1.37.0
- Update go.opentelemetry.io/otel/trace from v1.36.0 to v1.37.0
- Update go.opentelemetry.io/otel/metric from v1.36.0 to v1.37.0
- Update github.com/go-logr/logr from v1.4.2 to v1.4.3
Co-Authored-By: Flc゛ <four_leaf_clover@foxmail.com>
- Complete TODO in OnEndWithStreamOutput following existing patterns
- Add proper span state handling and cleanup
- Maintain consistency with OnEnd method implementation

Co-Authored-By: Flc゛ <four_leaf_clover@foxmail.com>
Copy link

codecov bot commented Jul 31, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 65.7%. Comparing base (283b2fe) to head (2b223ba).
⚠️ Report is 67 commits behind head on 3.x.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             3.x   #1170     +/-   ##
=======================================
- Coverage   65.8%   65.7%   -0.1%     
=======================================
  Files        137     137             
  Lines       5670    5677      +7     
=======================================
  Hits        3733    3733             
- Misses      1860    1867      +7     
  Partials      77      77             

see 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant