Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions docs/runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -1400,7 +1400,7 @@ client.Run(ctx, "session-1", msgs,
runtime.WithMetadata(map[string]any{"request_id": "abc"}),
runtime.WithTaskQueue("custom-queue"),
runtime.WithMemo(map[string]any{"workflow_name": "Chat"}),
runtime.WithSearchAttributes(map[string]any{"SessionID": "s1"}),
runtime.WithSearchAttributes(map[string]any{"tenant": "acme"}),
runtime.WithTiming(runtime.Timing{
Budget: 2 * time.Minute,
Plan: 30 * time.Second,
Expand All @@ -1409,6 +1409,10 @@ client.Run(ctx, "session-1", msgs,
)
```

Search attributes are passed through to the workflow engine as caller-owned
index metadata. The runtime does not mirror `SessionID` into engine search
attributes automatically.

`Timing.Plan` and `Timing.Tools` are semantic attempt budgets. They bound how
long a healthy planner or tool attempt may run once execution starts. Queue-wait
timeouts and heartbeat-based liveness detection are engine-specific concerns and
Expand Down Expand Up @@ -1860,8 +1864,8 @@ var ErrRateLimited = errors.New("model: rate limited")
3. **Choose one streaming path.** Either use the decorated model client OR
`planner.ConsumeStream`, never both.

4. **Set SessionID.** Every run requires a session ID for proper grouping and
memory association.
4. **Set SessionID for sessionful runs.** `Run` and `Start` require a session ID
for grouping and memory association. `OneShotRun` is explicitly sessionless.

5. **Trust the contracts.** Don't add defensive checks for values guaranteed by
Goa validation or construction. Let violations fail fast.
Expand Down
4 changes: 0 additions & 4 deletions runtime/agent/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -1392,13 +1392,9 @@ func (r *Runtime) startRunOn(ctx context.Context, input *RunInput, workflowName,
}
}
if requireSession {
if req.SearchAttributes == nil {
req.SearchAttributes = make(map[string]any, 1)
}
if v, ok := req.SearchAttributes["SessionID"]; ok && v != input.SessionID {
return nil, fmt.Errorf("workflow search attribute SessionID=%v does not match session id %q", v, input.SessionID)
}
req.SearchAttributes["SessionID"] = input.SessionID
now := time.Now().UTC()
if err := r.SessionStore.UpsertRun(ctx, session.RunMeta{
AgentID: string(input.AgentID),
Expand Down
23 changes: 21 additions & 2 deletions runtime/agent/runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ func TestStartRunRequiresSessionID(t *testing.T) {
require.NoError(t, err)
}

func TestStartRunDoesNotInjectSessionSearchAttribute(t *testing.T) {
eng := &stubEngine{}
rt := &Runtime{
Engine: eng,
logger: telemetry.NoopLogger{},
metrics: telemetry.NoopMetrics{},
tracer: telemetry.NoopTracer{},
SessionStore: sessioninmem.New(),
agents: map[agent.Ident]AgentRegistration{
"service.agent": {ID: "service.agent", Workflow: engine.WorkflowDefinition{Name: "service.workflow", TaskQueue: "q"}},
},
}
client := rt.MustClient(agent.Ident("service.agent"))
_, err := rt.CreateSession(context.Background(), "sess-1")
require.NoError(t, err)
_, err = client.Start(context.Background(), "sess-1", nil)
require.NoError(t, err)
require.Nil(t, eng.last.SearchAttributes)
}

func TestFinishWithoutToolCalls_UsesPlannerFinalToolResult(t *testing.T) {
rt := &Runtime{
logger: telemetry.NoopLogger{},
Expand Down Expand Up @@ -524,8 +544,7 @@ func TestStartRunForwardsWorkflowOptions(t *testing.T) {
require.Equal(t, in.RunID, eng.last.ID)
require.Equal(t, in.WorkflowOptions.Memo, eng.last.Memo)
require.Equal(t, map[string]any{
"SessionID": in.SessionID,
"sa": "x",
"sa": "x",
}, eng.last.SearchAttributes)
require.Equal(t, 5, eng.last.RetryPolicy.MaxAttempts)
require.Equal(t, 5*time.Second, eng.last.RetryPolicy.InitialInterval)
Expand Down
Loading