FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
sim/scripts/sync-tool-catalog.ts at main · simstudioai/sim · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
simstudioai
/
sim
Public
Notifications
You must be signed in to change notification settings
Fork
3.8k
Star
29.5k
Code
Issues
119
Pull requests
178
Actions
Projects
Security and quality
0
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
sim
/
scripts
/
sync-tool-catalog.ts
Copy path
More file actions
More file actions
Latest commit
History
History
History
234 lines (205 loc) · 7.57 KB
Breadcrumbs
sim
/
scripts
/
sync-tool-catalog.ts
Copy path
File metadata and controls
234 lines (205 loc) · 7.57 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import
{
mkdir
,
readFile
,
writeFile
}
from
'node:fs/promises'
import
{
dirname
,
resolve
}
from
'node:path'
import
{
fileURLToPath
}
from
'node:url'
import
{
formatGeneratedSource
}
from
'./format-generated-source'
const
SCRIPT_DIR
=
dirname
(
fileURLToPath
(
import
.
meta
.
url
)
)
const
ROOT
=
resolve
(
SCRIPT_DIR
,
'..'
)
const
DEFAULT_CATALOG_PATH
=
resolve
(
ROOT
,
'../copilot/copilot/contracts/tool-catalog-v1.json'
)
const
OUTPUT_PATH
=
resolve
(
ROOT
,
'apps/sim/lib/copilot/generated/tool-catalog-v1.ts'
)
const
RUNTIME_SCHEMA_OUTPUT_PATH
=
resolve
(
ROOT
,
'apps/sim/lib/copilot/generated/tool-schemas-v1.ts'
)
function
snakeToPascal
(
s
:
string
)
:
string
{
return
s
.
split
(
'_'
)
.
map
(
(
w
)
=>
w
.
charAt
(
0
)
.
toUpperCase
(
)
+
w
.
slice
(
1
)
)
.
join
(
''
)
}
function
toCamelIdentifier
(
value
:
string
)
:
string
{
const
parts
=
value
.
split
(
/
[
^
a
-
z
A
-
Z
0
-
9
]
+
/
)
.
filter
(
Boolean
)
if
(
parts
.
length
===
0
)
return
'value'
const
camel
=
parts
.
map
(
(
part
,
index
)
=>
{
const
lower
=
part
.
toLowerCase
(
)
if
(
index
===
0
)
return
lower
return
lower
.
charAt
(
0
)
.
toUpperCase
(
)
+
lower
.
slice
(
1
)
}
)
.
join
(
''
)
return
/
^
[
0
-
9
]
/
.
test
(
camel
)
?
`v
${
camel
}
`
:
camel
}
function
getTopLevelOperationEnum
(
tool
:
Record
<
string
,
unknown
>
)
:
string
[
]
|
undefined
{
const
parameters
=
typeof
tool
.
parameters
===
'object'
&&
tool
.
parameters
!==
null
?
(
tool
.
parameters
as
Record
<
string
,
unknown
>
)
:
null
const
properties
=
parameters
&&
typeof
parameters
.
properties
===
'object'
&&
parameters
.
properties
!==
null
?
(
parameters
.
properties
as
Record
<
string
,
unknown
>
)
:
null
const
operation
=
properties
&&
typeof
properties
.
operation
===
'object'
&&
properties
.
operation
!==
null
?
(
properties
.
operation
as
Record
<
string
,
unknown
>
)
:
null
const
values
=
operation
?.
enum
if
(
!
Array
.
isArray
(
values
)
||
values
.
some
(
(
value
)
=>
typeof
value
!==
'string'
)
)
{
return
undefined
}
return
values
as
string
[
]
}
function
inferTSType
(
values
:
unknown
[
]
)
:
string
{
const
unique
=
[
...
new
Set
(
values
.
filter
(
(
v
)
=>
v
!==
undefined
&&
v
!==
null
)
)
]
if
(
unique
.
length
===
0
)
return
'string'
if
(
unique
.
every
(
(
v
)
=>
typeof
v
===
'string'
)
)
{
return
unique
.
map
(
(
v
)
=>
JSON
.
stringify
(
v
)
)
.
sort
(
)
.
join
(
' | '
)
}
if
(
unique
.
every
(
(
v
)
=>
typeof
v
===
'boolean'
)
)
return
'boolean'
if
(
unique
.
every
(
(
v
)
=>
typeof
v
===
'number'
)
)
return
'number'
return
'unknown'
}
function
renderRuntimeSchemaModule
(
catalog
:
{
tools
:
Record
<
string
,
unknown
>
[
]
}
)
:
string
{
const
lines
:
string
[
]
=
[
'// AUTO-GENERATED FILE. DO NOT EDIT.'
,
'// Generated from copilot/contracts/tool-catalog-v1.json'
,
'//'
,
''
,
'export type JsonSchema = unknown'
,
''
,
'export interface ToolRuntimeSchemaEntry {'
,
' parameters?: JsonSchema;'
,
' resultSchema?: JsonSchema;'
,
'}'
,
''
,
'export const TOOL_RUNTIME_SCHEMAS: Record<string, ToolRuntimeSchemaEntry> = {'
,
]
for
(
const
tool
of
catalog
.
tools
)
{
const
id
=
JSON
.
stringify
(
tool
.
id
)
const
parameters
=
'parameters'
in
tool
?
JSON
.
stringify
(
tool
.
parameters
??
null
,
null
,
2
)
:
'undefined'
const
resultSchema
=
'resultSchema'
in
tool
?
JSON
.
stringify
(
tool
.
resultSchema
??
null
,
null
,
2
)
:
'undefined'
lines
.
push
(
`
${
id
}
: {`
)
lines
.
push
(
` parameters:
${
parameters
===
'null'
?
'undefined'
:
parameters
.
replace
(
/
\n
/
g
,
'\n '
)
}
,`
)
lines
.
push
(
` resultSchema:
${
resultSchema
===
'null'
?
'undefined'
:
resultSchema
.
replace
(
/
\n
/
g
,
'\n '
)
}
,`
)
lines
.
push
(
' },'
)
}
lines
.
push
(
'}'
)
lines
.
push
(
''
)
return
lines
.
join
(
'\n'
)
}
function
generateInterface
(
tools
:
Record
<
string
,
unknown
>
[
]
)
:
string
{
if
(
tools
.
length
===
0
)
return
'export interface ToolCatalogEntry {}\n'
const
allKeys
=
new
Set
<
string
>
(
)
for
(
const
tool
of
tools
)
{
for
(
const
key
of
Object
.
keys
(
tool
)
)
{
allKeys
.
add
(
key
)
}
}
const
requiredKeys
=
new
Set
<
string
>
(
)
for
(
const
key
of
allKeys
)
{
if
(
tools
.
every
(
(
t
)
=>
key
in
t
)
)
{
requiredKeys
.
add
(
key
)
}
}
const
lines
:
string
[
]
=
[
'export interface ToolCatalogEntry {'
]
for
(
const
key
of
[
...
allKeys
]
.
sort
(
)
)
{
const
values
=
tools
.
map
(
(
t
)
=>
t
[
key
]
)
const
tsType
=
inferTSType
(
values
)
const
optional
=
requiredKeys
.
has
(
key
)
?
''
:
'?'
lines
.
push
(
`
${
key
}
${
optional
}
:
${
tsType
}
;`
)
}
lines
.
push
(
'}'
)
return
lines
.
join
(
'\n'
)
}
async
function
main
(
)
{
const
checkOnly
=
process
.
argv
.
includes
(
'--check'
)
const
inputPathArg
=
process
.
argv
.
find
(
(
arg
)
=>
arg
.
startsWith
(
'--input='
)
)
const
inputPath
=
inputPathArg
?
resolve
(
ROOT
,
inputPathArg
.
slice
(
'--input='
.
length
)
)
:
DEFAULT_CATALOG_PATH
const
raw
=
await
readFile
(
inputPath
,
'utf8'
)
const
catalog
=
JSON
.
parse
(
raw
)
as
{
version
:
string
;
tools
:
Record
<
string
,
unknown
>
[
]
}
const
iface
=
generateInterface
(
catalog
.
tools
)
const
lines
:
string
[
]
=
[
'// AUTO-GENERATED FILE. DO NOT EDIT.'
,
'// Generated from copilot/contracts/tool-catalog-v1.json'
,
'//'
,
''
,
iface
,
''
,
]
const
constNames
:
string
[
]
=
[
]
for
(
const
tool
of
catalog
.
tools
)
{
const
constName
=
snakeToPascal
(
tool
.
id
as
string
)
constNames
.
push
(
constName
)
const
fields
:
string
[
]
=
[
]
for
(
const
[
key
,
value
]
of
Object
.
entries
(
tool
)
)
{
fields
.
push
(
`
${
key
}
:
${
JSON
.
stringify
(
value
)
}
`
)
}
lines
.
push
(
`export const
${
constName
}
: ToolCatalogEntry = {`
)
lines
.
push
(
`
${
fields
.
join
(
',\n'
)
}
,`
)
lines
.
push
(
'};'
)
lines
.
push
(
''
)
}
for
(
const
tool
of
catalog
.
tools
)
{
const
constName
=
snakeToPascal
(
tool
.
id
as
string
)
const
operationEnum
=
getTopLevelOperationEnum
(
tool
)
if
(
!
operationEnum
||
operationEnum
.
length
===
0
)
continue
const
operationConstName
=
`
${
constName
}
Operation`
const
seenKeys
=
new
Set
<
string
>
(
)
const
members
=
operationEnum
.
map
(
(
value
,
index
)
=>
{
let
key
=
toCamelIdentifier
(
value
)
if
(
seenKeys
.
has
(
key
)
)
key
=
`
${
key
}
${
index
+
1
}
`
seenKeys
.
add
(
key
)
return
{
key
,
value
}
}
)
lines
.
push
(
`export const
${
operationConstName
}
= {`
)
for
(
const
member
of
members
)
{
lines
.
push
(
`
${
member
.
key
}
:
${
JSON
.
stringify
(
member
.
value
)
}
,`
)
}
lines
.
push
(
'} as const;'
)
lines
.
push
(
''
)
lines
.
push
(
`export type
${
operationConstName
}
= (typeof
${
operationConstName
}
)[keyof typeof
${
operationConstName
}
];`
)
lines
.
push
(
''
)
lines
.
push
(
`export const
${
operationConstName
}
Values = [`
)
for
(
const
member
of
members
)
{
lines
.
push
(
`
${
operationConstName
}
.
${
member
.
key
}
,`
)
}
lines
.
push
(
`] as const;`
)
lines
.
push
(
''
)
}
lines
.
push
(
`export const TOOL_CATALOG: Record<string, ToolCatalogEntry> = {`
)
for
(
let
i
=
0
;
i
<
catalog
.
tools
.
length
;
i
++
)
{
lines
.
push
(
` [
${
constNames
[
i
]
}
.id]:
${
constNames
[
i
]
}
,`
)
}
lines
.
push
(
'};'
)
lines
.
push
(
''
)
const
rendered
=
formatGeneratedSource
(
lines
.
join
(
'\n'
)
,
OUTPUT_PATH
,
ROOT
)
const
runtimeSchemaRendered
=
formatGeneratedSource
(
renderRuntimeSchemaModule
(
catalog
)
,
RUNTIME_SCHEMA_OUTPUT_PATH
,
ROOT
)
if
(
checkOnly
)
{
const
existing
=
await
readFile
(
OUTPUT_PATH
,
'utf8'
)
.
catch
(
(
)
=>
null
)
const
existingRuntime
=
await
readFile
(
RUNTIME_SCHEMA_OUTPUT_PATH
,
'utf8'
)
.
catch
(
(
)
=>
null
)
if
(
existing
!==
rendered
||
existingRuntime
!==
runtimeSchemaRendered
)
{
throw
new
Error
(
`Generated tool catalog is stale. Run: bun run mship-tools:generate`
)
}
return
}
await
mkdir
(
dirname
(
OUTPUT_PATH
)
,
{
recursive
:
true
}
)
await
writeFile
(
OUTPUT_PATH
,
rendered
,
'utf8'
)
await
mkdir
(
dirname
(
RUNTIME_SCHEMA_OUTPUT_PATH
)
,
{
recursive
:
true
}
)
await
writeFile
(
RUNTIME_SCHEMA_OUTPUT_PATH
,
runtimeSchemaRendered
,
'utf8'
)
}
await
main
(
)
Back
|
FazBrowse Home
|
New Git URL