diff --git a/packages/client/workbench/src/settings/providers/__tests__/add-flow.test.tsx b/packages/client/workbench/src/settings/providers/__tests__/add-flow.test.tsx
index 461322c5..1de5d126 100644
--- a/packages/client/workbench/src/settings/providers/__tests__/add-flow.test.tsx
+++ b/packages/client/workbench/src/settings/providers/__tests__/add-flow.test.tsx
@@ -165,6 +165,40 @@ describe('non-subscription account creation', () => {
);
});
+ it('offers a dedicated StepFun API key entry', async () => {
+ const onPick = vi.fn();
+ render();
+ fireEvent.click(screen.getByText('serviceName.stepfun'));
+ expect(onPick).toHaveBeenCalledWith('stepfun');
+ cleanup();
+
+ const onSubmit = vi.fn();
+ render(
+ ,
+ );
+
+ const secret = document.querySelector('input[type="password"]');
+ if (!secret) throw new Error('credential input missing');
+ fireEvent.change(secret, { target: { value: 'stepfun-test-key' } });
+ fireEvent.click(screen.getByRole('button', { name: 'form.submit' }));
+
+ await waitFor(() =>
+ expect(onSubmit).toHaveBeenCalledWith(
+ expect.objectContaining({
+ service: 'stepfun',
+ credential: { type: 'api-key', key: 'stepfun-test-key' },
+ }),
+ ),
+ );
+ });
+
it('asks nothing about protocol for a service serving several shapes', () => {
render(
{
});
});
+ it('routes a StepFun key over each supported native protocol', () => {
+ const stepfun = account({ service: 'stepfun' });
+ expect(resolveBinding(stepfun, 'claude-code')).toEqual({
+ tier: 'native',
+ protocol: 'anthropic',
+ baseUrl: 'https://api.stepfun.com',
+ });
+ expect(resolveBinding(stepfun, 'codex')).toEqual({
+ tier: 'native',
+ protocol: 'openai-responses',
+ baseUrl: 'https://api.stepfun.com/v1',
+ });
+ expect(resolveBinding(stepfun, 'opencode')).toEqual({
+ tier: 'native',
+ protocol: 'openai-chat',
+ baseUrl: 'https://api.stepfun.com/v1',
+ knownProvider: 'stepfun',
+ });
+ expect(resolveBinding(stepfun, 'pi')).toEqual({
+ tier: 'native',
+ protocol: 'anthropic',
+ baseUrl: 'https://api.stepfun.com',
+ });
+ expect(resolveBinding(stepfun, 'grok-build')).toEqual({
+ tier: 'unavailable',
+ reason: 'protocol-unsupported',
+ });
+ });
+
it('reaches codex on every service whose endpoint serves the Responses API', () => {
// Verified against vendor docs 2026-08: xAI, OpenRouter and Vercel all serve POST /responses
// at the base URL declared here, so codex must have a target on each.
@@ -305,6 +334,10 @@ describe('catalog helpers', () => {
url: 'https://api.deepseek.com/models',
wire: 'openai',
});
+ expect(modelListSource('stepfun')).toEqual({
+ url: 'https://api.stepfun.com/v1/models',
+ wire: 'openai',
+ });
expect(modelListSource('anthropic-api')?.wire).toBe('anthropic');
expect(modelListSource('linkcode-gateway')).toEqual({
url: 'https://gateway.linkcode.ai/v1/models',
diff --git a/packages/foundation/providers/src/catalog.ts b/packages/foundation/providers/src/catalog.ts
index 0dd7653d..c375ce20 100644
--- a/packages/foundation/providers/src/catalog.ts
+++ b/packages/foundation/providers/src/catalog.ts
@@ -133,6 +133,24 @@ export const SERVICE_CATALOG: ServiceDescriptor[] = [
models: { url: 'https://api.deepseek.com/models', wire: 'openai' },
secretPlaceholder: 'sk-…',
},
+ {
+ id: 'stepfun',
+ label: 'StepFun',
+ group: 'direct',
+ kind: 'endpoint',
+ credentialType: 'api-key',
+ variants: {
+ anthropic: { baseUrl: 'https://api.stepfun.com' },
+ // Responses serves `step-3.7-flash` only (2026-08).
+ 'openai-responses': { baseUrl: 'https://api.stepfun.com/v1' },
+ 'openai-chat': {
+ baseUrl: 'https://api.stepfun.com/v1',
+ knownProvider: { opencode: 'stepfun' },
+ },
+ },
+ models: { url: 'https://api.stepfun.com/v1/models', wire: 'openai' },
+ secretPlaceholder: 'sk-…',
+ },
{
id: LINKCODE_GATEWAY_SERVICE_ID,
label: 'LinkCode Gateway',
diff --git a/packages/presentation/i18n/src/locales/en.ts b/packages/presentation/i18n/src/locales/en.ts
index 56de73e2..6afb6446 100644
--- a/packages/presentation/i18n/src/locales/en.ts
+++ b/packages/presentation/i18n/src/locales/en.ts
@@ -1116,6 +1116,7 @@ export const en = {
'openai-api': 'OpenAI API',
xai: 'xAI (Grok)',
deepseek: 'DeepSeek',
+ stepfun: 'StepFun',
openrouter: 'OpenRouter',
'vercel-gateway': 'Vercel AI Gateway',
'cloudflare-gateway': 'Cloudflare AI Gateway',
@@ -1130,6 +1131,7 @@ export const en = {
'openai-api': 'A key from platform.openai.com',
xai: 'A key from console.x.ai',
deepseek: 'A key from platform.deepseek.com',
+ stepfun: 'A key from platform.stepfun.com',
'linkcode-gateway': 'Use LinkCode credits without bringing an API key',
openrouter: 'Aggregation gateway',
'vercel-gateway': 'Server-side translating gateway',
diff --git a/packages/presentation/i18n/src/locales/zh-cn.ts b/packages/presentation/i18n/src/locales/zh-cn.ts
index ea900389..6dda1827 100644
--- a/packages/presentation/i18n/src/locales/zh-cn.ts
+++ b/packages/presentation/i18n/src/locales/zh-cn.ts
@@ -1089,6 +1089,7 @@ export const zhCN = {
'openai-api': 'OpenAI API',
xai: 'xAI(Grok)',
deepseek: 'DeepSeek',
+ stepfun: '阶跃星辰 StepFun',
openrouter: 'OpenRouter',
'vercel-gateway': 'Vercel AI Gateway',
'cloudflare-gateway': 'Cloudflare AI Gateway',
@@ -1103,6 +1104,7 @@ export const zhCN = {
'openai-api': 'platform.openai.com 的密钥',
xai: 'console.x.ai 的密钥',
deepseek: 'platform.deepseek.com 的密钥',
+ stepfun: 'platform.stepfun.com 的密钥',
'linkcode-gateway': '无需自带 API 密钥,直接使用 LinkCode 额度',
openrouter: '聚合网关',
'vercel-gateway': '服务端翻译网关',
diff --git a/packages/presentation/ui/src/shell/service-icon.tsx b/packages/presentation/ui/src/shell/service-icon.tsx
index 6a72d3c5..5c011a89 100644
--- a/packages/presentation/ui/src/shell/service-icon.tsx
+++ b/packages/presentation/ui/src/shell/service-icon.tsx
@@ -6,6 +6,7 @@ import CloudflareColorGlyph from '~icons/lobe-icons/cloudflare-color';
import DeepSeekColorGlyph from '~icons/lobe-icons/deepseek-color';
import OpenAiGlyph from '~icons/lobe-icons/openai';
import OpenRouterGlyph from '~icons/lobe-icons/openrouter';
+import StepFunColorGlyph from '~icons/lobe-icons/stepfun-color';
import VercelGlyph from '~icons/lobe-icons/vercel';
import XaiGlyph from '~icons/lobe-icons/xai';
import { cn } from '../lib/cn';
@@ -32,6 +33,7 @@ const SERVICE_GLYPHS: Record = {
'openai-api': OpenAiGlyph,
xai: XaiGlyph,
deepseek: DeepSeekColorGlyph,
+ stepfun: StepFunColorGlyph,
openrouter: OpenRouterGlyph,
'vercel-gateway': VercelGlyph,
'cloudflare-gateway': CloudflareColorGlyph,