fix!: rename chat stream silence timeout error (#25973)

Renames the Agents chat stream-silence error from `startup_timeout` to
`stream_silence_timeout` now that the timeout applies to any gap between
provider stream parts, not just first-token startup.

Updates the SDK enum, generated API docs/types, chat error copy, and
Agents UI stories/status labels so the user-facing wording describes a
stalled provider response instead of startup delay.

> **Breaking change:** This is a very minor breaking change for the
Coder Agents API: the public chat error kind enum no longer includes
`startup_timeout`, so clients matching that specific value should handle
`stream_silence_timeout` instead.
This commit is contained in:
Ethan
2026-06-04 18:36:02 +10:00
committed by GitHub
parent b7635b5036
commit 3ab1323bc9
15 changed files with 65 additions and 65 deletions
+2 -2
View File
@@ -16723,7 +16723,7 @@ const docTemplate = `{
"overloaded",
"rate_limit",
"timeout",
"startup_timeout",
"stream_silence_timeout",
"auth",
"config",
"usage_limit",
@@ -16735,7 +16735,7 @@ const docTemplate = `{
"ChatErrorKindOverloaded",
"ChatErrorKindRateLimit",
"ChatErrorKindTimeout",
"ChatErrorKindStartupTimeout",
"ChatErrorKindStreamSilenceTimeout",
"ChatErrorKindAuth",
"ChatErrorKindConfig",
"ChatErrorKindUsageLimit",
+2 -2
View File
@@ -15049,7 +15049,7 @@
"overloaded",
"rate_limit",
"timeout",
"startup_timeout",
"stream_silence_timeout",
"auth",
"config",
"usage_limit",
@@ -15061,7 +15061,7 @@
"ChatErrorKindOverloaded",
"ChatErrorKindRateLimit",
"ChatErrorKindTimeout",
"ChatErrorKindStartupTimeout",
"ChatErrorKindStreamSilenceTimeout",
"ChatErrorKindAuth",
"ChatErrorKindConfig",
"ChatErrorKindUsageLimit",
+4 -4
View File
@@ -981,21 +981,21 @@ func TestClassify_StatusCodeBeatsHTTP2Transport(t *testing.T) {
}
}
func TestClassify_StartupTimeoutWrappedClassificationWins(t *testing.T) {
func TestClassify_StreamSilenceTimeoutWrappedClassificationWins(t *testing.T) {
t.Parallel()
wrapped := chaterror.WithClassification(
xerrors.New("context canceled"),
chaterror.ClassifiedError{
Kind: codersdk.ChatErrorKindStartupTimeout,
Kind: codersdk.ChatErrorKindStreamSilenceTimeout,
Provider: "openai",
Retryable: true,
},
)
require.Equal(t, chaterror.ClassifiedError{
Message: "OpenAI did not start responding in time.",
Kind: codersdk.ChatErrorKindStartupTimeout,
Message: "OpenAI did not send response data in time.",
Kind: codersdk.ChatErrorKindStreamSilenceTimeout,
Provider: "openai",
Retryable: true,
StatusCode: 0,
+4 -4
View File
@@ -28,9 +28,9 @@ func terminalMessage(classified ClassifiedError) string {
}
return stringutil.Capitalize(fmt.Sprintf("%s is temporarily unavailable.", subject))
case codersdk.ChatErrorKindStartupTimeout:
case codersdk.ChatErrorKindStreamSilenceTimeout:
return stringutil.Capitalize(fmt.Sprintf(
"%s did not start responding in time.", subject,
"%s did not send response data in time.", subject,
))
case codersdk.ChatErrorKindUsageLimit:
@@ -89,9 +89,9 @@ func retryMessage(classified ClassifiedError) string {
return stringutil.Capitalize(fmt.Sprintf("%s is rate limiting requests.", subject))
case codersdk.ChatErrorKindTimeout:
return stringutil.Capitalize(fmt.Sprintf("%s is temporarily unavailable.", subject))
case codersdk.ChatErrorKindStartupTimeout:
case codersdk.ChatErrorKindStreamSilenceTimeout:
return stringutil.Capitalize(fmt.Sprintf(
"%s did not start responding in time.", subject,
"%s did not send response data in time.", subject,
))
case codersdk.ChatErrorKindAuth:
return fmt.Sprintf(
+7 -7
View File
@@ -11,7 +11,7 @@ import (
)
// TestTerminalMessage covers the per-provider "temporarily
// unavailable" copy, the startup-timeout copy, and the generic
// unavailable" copy, the stream-silence timeout copy, and the generic
// fallback string for its intended (unclassified, non-retryable)
// path.
func TestTerminalMessage(t *testing.T) {
@@ -54,18 +54,18 @@ func TestTerminalMessage(t *testing.T) {
want: "The request timed out before it completed.",
},
{
name: "StartupTimeout_Anthropic",
kind: codersdk.ChatErrorKindStartupTimeout,
name: "StreamSilenceTimeout_Anthropic",
kind: codersdk.ChatErrorKindStreamSilenceTimeout,
provider: "anthropic",
retryable: true,
want: "Anthropic did not start responding in time.",
want: "Anthropic did not send response data in time.",
},
{
name: "StartupTimeout_OpenAI",
kind: codersdk.ChatErrorKindStartupTimeout,
name: "StreamSilenceTimeout_OpenAI",
kind: codersdk.ChatErrorKindStreamSilenceTimeout,
provider: "openai",
retryable: true,
want: "OpenAI did not start responding in time.",
want: "OpenAI did not send response data in time.",
},
{
// Generic fallback reserved for genuinely
+1 -1
View File
@@ -867,7 +867,7 @@ func classifyStreamSilenceTimeout(
err = errStreamSilenceTimeout
}
return chaterror.WithClassification(err, chaterror.ClassifiedError{
Kind: codersdk.ChatErrorKindStartupTimeout,
Kind: codersdk.ChatErrorKindStreamSilenceTimeout,
Provider: provider,
Retryable: true,
})
@@ -700,12 +700,12 @@ func TestRun_RetriesSilenceTimeoutWhileOpeningStream(t *testing.T) {
require.NoError(t, awaitRunResult(ctx, t, done))
require.Equal(t, 2, attempts)
require.Len(t, retries, 1)
require.Equal(t, codersdk.ChatErrorKindStartupTimeout, retries[0].Kind)
require.Equal(t, codersdk.ChatErrorKindStreamSilenceTimeout, retries[0].Kind)
require.True(t, retries[0].Retryable)
require.Equal(t, "openai", retries[0].Provider)
require.Equal(
t,
"OpenAI did not start responding in time.",
"OpenAI did not send response data in time.",
retries[0].Message,
)
select {
@@ -930,12 +930,12 @@ func TestRun_RetriesSilenceTimeoutBeforeFirstPart(t *testing.T) {
require.NoError(t, awaitRunResult(ctx, t, done))
require.Equal(t, 2, attempts)
require.Len(t, retries, 1)
require.Equal(t, codersdk.ChatErrorKindStartupTimeout, retries[0].Kind)
require.Equal(t, codersdk.ChatErrorKindStreamSilenceTimeout, retries[0].Kind)
require.True(t, retries[0].Retryable)
require.Equal(t, "openai", retries[0].Provider)
require.Equal(
t,
"OpenAI did not start responding in time.",
"OpenAI did not send response data in time.",
retries[0].Message,
)
select {
@@ -1161,7 +1161,7 @@ func TestRun_RetriesSilenceTimeoutBetweenParts(t *testing.T) {
require.NoError(t, awaitRunResult(ctx, t, done))
require.Equal(t, 2, attempts)
require.Len(t, retries, 1)
require.Equal(t, codersdk.ChatErrorKindStartupTimeout, retries[0].Kind)
require.Equal(t, codersdk.ChatErrorKindStreamSilenceTimeout, retries[0].Kind)
require.True(t, retries[0].Retryable)
require.Equal(t, "openai", retries[0].Provider)
select {
@@ -1278,12 +1278,12 @@ func TestRun_RetriesSilenceTimeoutWhenStreamStaysSilent(t *testing.T) {
require.NoError(t, awaitRunResult(ctx, t, done))
require.Equal(t, 2, attempts)
require.Len(t, retries, 1)
require.Equal(t, codersdk.ChatErrorKindStartupTimeout, retries[0].Kind)
require.Equal(t, codersdk.ChatErrorKindStreamSilenceTimeout, retries[0].Kind)
require.True(t, retries[0].Retryable)
require.Equal(t, "openai", retries[0].Provider)
require.Equal(
t,
"OpenAI did not start responding in time.",
"OpenAI did not send response data in time.",
retries[0].Message,
)
select {
+1 -1
View File
@@ -293,7 +293,7 @@ func TestRecordStreamRetry(t *testing.T) {
{name: "overloaded", kind: codersdk.ChatErrorKindOverloaded},
{name: "rate_limit", kind: codersdk.ChatErrorKindRateLimit},
{name: "timeout", kind: codersdk.ChatErrorKindTimeout},
{name: "startup_timeout", kind: codersdk.ChatErrorKindStartupTimeout},
{name: "stream_silence_timeout", kind: codersdk.ChatErrorKindStreamSilenceTimeout},
{name: "auth", kind: codersdk.ChatErrorKindAuth},
{name: "config", kind: codersdk.ChatErrorKindConfig},
{name: "missing_key", kind: codersdk.ChatErrorKindMissingKey},