-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Expand file tree
/
Copy pathsync-agent-stream-docs.ts
More file actions
185 lines (159 loc) · 6.53 KB
/
Copy pathsync-agent-stream-docs.ts
File metadata and controls
185 lines (159 loc) · 6.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/**
* Generates the "Streamed thinking and tool calls" support tables on the Agent
* block docs page from the provider registry, so the docs can never drift from
* the code:
*
* - Thinking visibility per model comes from `capabilities.thinking.streamed`
* (explicit) or the per-provider defaults in `getThinkingStreamVisibility`.
* - Live tool-call streaming comes from `STREAMING_TOOL_CALL_PROVIDERS`.
*
* Content is rewritten between the `agent-stream-capabilities` markers in
* `apps/docs/content/docs/en/workflows/blocks/agent.mdx`.
*
* Usage:
* bun run scripts/sync-agent-stream-docs.ts # write
* bun run scripts/sync-agent-stream-docs.ts --check # fail on drift or missing metadata
*/
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import {
getThinkingStreamVisibility,
PROVIDER_DEFINITIONS,
type ThinkingStreamVisibility,
} from '../apps/sim/providers/models'
import { STREAMING_TOOL_CALL_PROVIDERS } from '../apps/sim/providers/streaming-tool-loop-shared'
const __filename = fileURLToPath(import.meta.url)
const rootDir = path.resolve(path.dirname(__filename), '..')
const AGENT_DOC_PATH = path.join(rootDir, 'apps/docs/content/docs/en/workflows/blocks/agent.mdx')
const BEGIN_MARKER =
'{/* agent-stream-capabilities:begin — generated by `bun run agent-stream-docs:generate`; do not edit between markers */}'
const END_MARKER = '{/* agent-stream-capabilities:end */}'
/**
* Providers whose thinking visibility varies per model generation and must
* therefore be declared explicitly on every thinking-capable model.
*/
const EXPLICIT_VISIBILITY_PROVIDERS = new Set(['anthropic', 'azure-anthropic'])
const VISIBILITY_LABELS: Record<ThinkingStreamVisibility, string> = {
full: 'Full thinking deltas',
summary: 'Summaries only',
none: 'Not streamed',
}
const VISIBILITY_NOTES: Partial<Record<string, string>> = {
'openai:summary': 'Requires OpenAI organization verification; falls back to no summaries.',
'azure-openai:summary': 'Requires OpenAI organization verification; falls back to no summaries.',
'anthropic:summary':
'These generations omit full thinking; Sim requests summarized thinking on streaming runs.',
'azure-anthropic:summary':
'These generations omit full thinking; Sim requests summarized thinking on streaming runs.',
'anthropic:none': 'These model generations return thinking with omitted display by default.',
'azure-anthropic:none':
'These model generations return thinking with omitted display by default.',
'bedrock:none': 'Sim does not request reasoning on Bedrock.',
}
interface VisibilityRow {
providerName: string
visibility: ThinkingStreamVisibility
note: string
models: string[]
}
function buildVisibilityRows(): { rows: VisibilityRow[]; errors: string[] } {
const rows: VisibilityRow[] = []
const errors: string[] = []
for (const provider of Object.values(PROVIDER_DEFINITIONS)) {
const grouped = new Map<ThinkingStreamVisibility, string[]>()
for (const model of provider.models) {
if (model.sunset?.status === 'deprecated') continue
const reasoningCapable = model.capabilities.thinking || model.capabilities.reasoningEffort
if (!reasoningCapable) continue
if (
EXPLICIT_VISIBILITY_PROVIDERS.has(provider.id) &&
model.capabilities.thinking &&
model.capabilities.thinking.streamed === undefined
) {
errors.push(
`${provider.id}/${model.id}: thinking-capable models on this provider must declare capabilities.thinking.streamed ('full' | 'summary' | 'none') — visibility varies per Claude generation`
)
continue
}
const visibility = getThinkingStreamVisibility(model.id)
if (!visibility) continue
const models = grouped.get(visibility) ?? []
models.push(model.id)
grouped.set(visibility, models)
}
for (const visibility of ['full', 'summary', 'none'] as const) {
const models = grouped.get(visibility)
if (!models?.length) continue
rows.push({
providerName: provider.name,
visibility,
note: VISIBILITY_NOTES[`${provider.id}:${visibility}`] ?? '',
models,
})
}
}
return { rows, errors }
}
function buildGeneratedContent(): { content: string; errors: string[] } {
const { rows, errors } = buildVisibilityRows()
const liveToolProviders = Object.values(PROVIDER_DEFINITIONS)
.filter((provider) => STREAMING_TOOL_CALL_PROVIDERS.has(provider.id))
.map((provider) => provider.name)
const lines: string[] = []
lines.push('')
lines.push(
`Live tool-call chips stream for **${liveToolProviders.join(', ')}** models. Other providers run tools without live chips and project the settled final answer when the run completes; they do not ask the model to regenerate that answer just to create a stream.`
)
lines.push('')
lines.push('| Provider | Streamed thinking | Models |')
lines.push('|----------|-------------------|--------|')
for (const row of rows) {
const models = row.models.map((id) => `\`${id}\``).join(', ')
const visibility = row.note
? `${VISIBILITY_LABELS[row.visibility]} — ${row.note}`
: VISIBILITY_LABELS[row.visibility]
lines.push(`| ${row.providerName} | ${visibility} | ${models} |`)
}
lines.push('')
return { content: lines.join('\n'), errors }
}
function main(): void {
const checkMode = process.argv.includes('--check')
const { content, errors } = buildGeneratedContent()
if (errors.length > 0) {
console.error('agent-stream-docs: missing stream-visibility metadata:')
for (const error of errors) {
console.error(` - ${error}`)
}
process.exit(1)
}
const doc = fs.readFileSync(AGENT_DOC_PATH, 'utf8')
const beginIndex = doc.indexOf(BEGIN_MARKER)
const endIndex = doc.indexOf(END_MARKER)
if (beginIndex === -1 || endIndex === -1 || endIndex < beginIndex) {
console.error(
`agent-stream-docs: markers not found in ${path.relative(rootDir, AGENT_DOC_PATH)}`
)
process.exit(1)
}
const next =
doc.slice(0, beginIndex + BEGIN_MARKER.length) + `\n${content}\n` + doc.slice(endIndex)
if (checkMode) {
if (next !== doc) {
console.error(
'agent-stream-docs: docs are out of date — run `bun run agent-stream-docs:generate`'
)
process.exit(1)
}
console.log('agent-stream-docs: up to date.')
return
}
if (next !== doc) {
fs.writeFileSync(AGENT_DOC_PATH, next)
console.log(`agent-stream-docs: updated ${path.relative(rootDir, AGENT_DOC_PATH)}`)
} else {
console.log('agent-stream-docs: no changes.')
}
}
main()