retell-sync-cli 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.oxlintrc.json +12 -0
- package/.prettierrc.json +7 -0
- package/.todo +1 -0
- package/.vscode/settings.json +9 -0
- package/dist/cli.js +90828 -90258
- package/package.json +19 -17
- package/biome.json +0 -47
- package/test/getBaselineState.test.ts +0 -450
- package/test/getLocalState.test.ts +0 -382
- package/test/getRemoteState.test.ts +0 -196
package/package.json
CHANGED
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "retell-sync-cli",
|
|
3
|
-
"
|
|
4
|
-
"version": "1.1.0",
|
|
3
|
+
"version": "2.0.0",
|
|
5
4
|
"description": "CLI tool for syncing Retell AI agents between local filesystem and API",
|
|
6
|
-
"
|
|
7
|
-
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agents",
|
|
7
|
+
"ai",
|
|
8
|
+
"cli",
|
|
9
|
+
"retell",
|
|
10
|
+
"sync"
|
|
11
|
+
],
|
|
12
|
+
"author": "zachsents",
|
|
8
13
|
"bin": {
|
|
9
14
|
"retell": "./dist/cli.js"
|
|
10
15
|
},
|
|
16
|
+
"type": "module",
|
|
17
|
+
"main": "cli.ts",
|
|
11
18
|
"scripts": {
|
|
12
19
|
"check": "bunx tsc --noEmit && bun fix",
|
|
13
|
-
"fix": "
|
|
20
|
+
"fix": "oxlint --type-aware --fix-suggestions && prettier . --write",
|
|
14
21
|
"build": "bun build ./src/cli.ts --target bun --outdir dist"
|
|
15
22
|
},
|
|
16
|
-
"keywords": [
|
|
17
|
-
"retell",
|
|
18
|
-
"ai",
|
|
19
|
-
"cli",
|
|
20
|
-
"sync",
|
|
21
|
-
"agents"
|
|
22
|
-
],
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"@biomejs/biome": "^2.3.10",
|
|
25
|
-
"@types/bun": "latest",
|
|
26
|
-
"type-fest": "^5.3.1"
|
|
27
|
-
},
|
|
28
23
|
"dependencies": {
|
|
29
24
|
"@inquirer/prompts": "^8.1.0",
|
|
30
25
|
"boxen": "^8.0.1",
|
|
@@ -39,5 +34,12 @@
|
|
|
39
34
|
"retell-sdk": "^4.66.0",
|
|
40
35
|
"yaml": "^2.8.2",
|
|
41
36
|
"zod": "^4.2.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/bun": "latest",
|
|
40
|
+
"oxlint": "^1.35.0",
|
|
41
|
+
"oxlint-tsgolint": "^0.10.0",
|
|
42
|
+
"prettier-plugin-jsdoc": "^1.8.0",
|
|
43
|
+
"type-fest": "^5.3.1"
|
|
42
44
|
}
|
|
43
45
|
}
|
package/biome.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
|
|
3
|
-
"vcs": {
|
|
4
|
-
"enabled": true,
|
|
5
|
-
"clientKind": "git",
|
|
6
|
-
"useIgnoreFile": true
|
|
7
|
-
},
|
|
8
|
-
"files": {
|
|
9
|
-
"ignoreUnknown": true,
|
|
10
|
-
"includes": ["**", "!test/*.json"]
|
|
11
|
-
},
|
|
12
|
-
"formatter": {
|
|
13
|
-
"enabled": true,
|
|
14
|
-
"indentStyle": "space",
|
|
15
|
-
"indentWidth": 2
|
|
16
|
-
},
|
|
17
|
-
"linter": {
|
|
18
|
-
"enabled": true,
|
|
19
|
-
"rules": {
|
|
20
|
-
"recommended": true,
|
|
21
|
-
"suspicious": {
|
|
22
|
-
"noArrayIndexKey": "off",
|
|
23
|
-
"noConfusingVoidType": "off"
|
|
24
|
-
},
|
|
25
|
-
"style": {
|
|
26
|
-
"noNonNullAssertion": "off"
|
|
27
|
-
},
|
|
28
|
-
"complexity": {
|
|
29
|
-
"noCommaOperator": "off"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
"javascript": {
|
|
34
|
-
"formatter": {
|
|
35
|
-
"quoteStyle": "double",
|
|
36
|
-
"semicolons": "asNeeded"
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
"assist": {
|
|
40
|
-
"enabled": true,
|
|
41
|
-
"actions": {
|
|
42
|
-
"source": {
|
|
43
|
-
"organizeImports": "on"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -1,450 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
|
2
|
-
import fs from "node:fs/promises"
|
|
3
|
-
import os from "node:os"
|
|
4
|
-
import path from "node:path"
|
|
5
|
-
import { $ } from "bun"
|
|
6
|
-
import { getBaselineState } from "../src/lib/agents"
|
|
7
|
-
|
|
8
|
-
describe("getBaselineState", () => {
|
|
9
|
-
let tmpDir: string
|
|
10
|
-
let originalCwd: string
|
|
11
|
-
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
originalCwd = process.cwd()
|
|
14
|
-
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "retell-sync-test-"))
|
|
15
|
-
process.chdir(tmpDir)
|
|
16
|
-
|
|
17
|
-
// Initialize git repo
|
|
18
|
-
await $`git init`.quiet()
|
|
19
|
-
await $`git config user.email "test@test.com"`.quiet()
|
|
20
|
-
await $`git config user.name "Test"`.quiet()
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
afterEach(async () => {
|
|
24
|
-
process.chdir(originalCwd)
|
|
25
|
-
await fs.rm(tmpDir, { recursive: true, force: true })
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test("hydrates retell-llm agent with file placeholders resolved", async () => {
|
|
29
|
-
const agentsDir = "agents"
|
|
30
|
-
const agentDir = `${agentsDir}/test_llm_agent_abc123`
|
|
31
|
-
|
|
32
|
-
// Create agent files
|
|
33
|
-
await fs.mkdir(path.join(tmpDir, agentDir), { recursive: true })
|
|
34
|
-
|
|
35
|
-
await Bun.write(
|
|
36
|
-
path.join(tmpDir, agentDir, ".agent.json"),
|
|
37
|
-
JSON.stringify({
|
|
38
|
-
id: "agent_abc123456789",
|
|
39
|
-
version: 1,
|
|
40
|
-
responseEngineVersion: 1,
|
|
41
|
-
}),
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
await Bun.write(
|
|
45
|
-
path.join(tmpDir, agentDir, "config.json"),
|
|
46
|
-
JSON.stringify(
|
|
47
|
-
{
|
|
48
|
-
channel: "voice",
|
|
49
|
-
agent_name: "Test LLM Agent",
|
|
50
|
-
response_engine: {
|
|
51
|
-
type: "retell-llm",
|
|
52
|
-
llm_id: "llm_test123",
|
|
53
|
-
version: 1,
|
|
54
|
-
},
|
|
55
|
-
voice_id: "11labs-Chloe",
|
|
56
|
-
},
|
|
57
|
-
null,
|
|
58
|
-
2,
|
|
59
|
-
),
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
await Bun.write(
|
|
63
|
-
path.join(tmpDir, agentDir, "llm.json"),
|
|
64
|
-
JSON.stringify(
|
|
65
|
-
{
|
|
66
|
-
model: "gpt-4.1",
|
|
67
|
-
general_prompt: "file://./general_prompt.md",
|
|
68
|
-
begin_message: "Hello!",
|
|
69
|
-
},
|
|
70
|
-
null,
|
|
71
|
-
2,
|
|
72
|
-
),
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
await Bun.write(
|
|
76
|
-
path.join(tmpDir, agentDir, "general_prompt.md"),
|
|
77
|
-
`---
|
|
78
|
-
some_meta: value
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
You are a helpful assistant.
|
|
82
|
-
|
|
83
|
-
Be friendly and professional.
|
|
84
|
-
`,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
// Commit the files
|
|
88
|
-
await $`git add .`.quiet()
|
|
89
|
-
await $`git commit -m "Add test agent"`.quiet()
|
|
90
|
-
const { stdout } = await $`git rev-parse HEAD`.quiet()
|
|
91
|
-
const commitHash = stdout.toString().trim()
|
|
92
|
-
|
|
93
|
-
// Create .sync.json
|
|
94
|
-
await Bun.write(
|
|
95
|
-
path.join(tmpDir, ".sync.json"),
|
|
96
|
-
JSON.stringify({ baseline: { commitHash } }, null, 2),
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
// Run getBaselineState
|
|
100
|
-
const result = await getBaselineState({ agentsDir })
|
|
101
|
-
|
|
102
|
-
// Verify results
|
|
103
|
-
expect(result.voiceAgents).toHaveLength(1)
|
|
104
|
-
expect(result.llms).toHaveLength(1)
|
|
105
|
-
expect(result.conversationFlows).toHaveLength(0)
|
|
106
|
-
|
|
107
|
-
const agent = result.voiceAgents[0]!
|
|
108
|
-
expect(agent.agent_name).toBe("Test LLM Agent")
|
|
109
|
-
expect(agent.response_engine.type).toBe("retell-llm")
|
|
110
|
-
expect(agent.voice_id).toBe("11labs-Chloe")
|
|
111
|
-
|
|
112
|
-
const llm = result.llms[0]!
|
|
113
|
-
expect(llm.model).toBe("gpt-4.1")
|
|
114
|
-
expect(llm.begin_message).toBe("Hello!")
|
|
115
|
-
// Verify file placeholder was resolved
|
|
116
|
-
expect(llm.general_prompt).toContain("You are a helpful assistant.")
|
|
117
|
-
expect(llm.general_prompt).toContain("Be friendly and professional.")
|
|
118
|
-
// Frontmatter should be stripped
|
|
119
|
-
expect(llm.general_prompt).not.toContain("some_meta")
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
test("hydrates conversation-flow agent with nested file placeholders", async () => {
|
|
123
|
-
const agentsDir = "agents"
|
|
124
|
-
const agentDir = `${agentsDir}/test_flow_agent_def456`
|
|
125
|
-
|
|
126
|
-
// Create agent files
|
|
127
|
-
await fs.mkdir(path.join(tmpDir, agentDir, "nodes"), { recursive: true })
|
|
128
|
-
|
|
129
|
-
await Bun.write(
|
|
130
|
-
path.join(tmpDir, agentDir, ".agent.json"),
|
|
131
|
-
JSON.stringify({
|
|
132
|
-
id: "agent_def456789012",
|
|
133
|
-
version: 2,
|
|
134
|
-
responseEngineVersion: 2,
|
|
135
|
-
}),
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
await Bun.write(
|
|
139
|
-
path.join(tmpDir, agentDir, "config.json"),
|
|
140
|
-
JSON.stringify(
|
|
141
|
-
{
|
|
142
|
-
channel: "voice",
|
|
143
|
-
agent_name: "Test Flow Agent",
|
|
144
|
-
response_engine: {
|
|
145
|
-
type: "conversation-flow",
|
|
146
|
-
conversation_flow_id: "flow_test456",
|
|
147
|
-
version: 2,
|
|
148
|
-
},
|
|
149
|
-
voice_id: "openai-Alloy",
|
|
150
|
-
},
|
|
151
|
-
null,
|
|
152
|
-
2,
|
|
153
|
-
),
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
await Bun.write(
|
|
157
|
-
path.join(tmpDir, agentDir, "conversation-flow.json"),
|
|
158
|
-
JSON.stringify(
|
|
159
|
-
{
|
|
160
|
-
global_prompt: "file://./global_prompt.md",
|
|
161
|
-
nodes: [
|
|
162
|
-
{
|
|
163
|
-
id: "start-node",
|
|
164
|
-
name: "Welcome",
|
|
165
|
-
type: "conversation",
|
|
166
|
-
instruction: {
|
|
167
|
-
type: "static_text",
|
|
168
|
-
text: "Hello, welcome!",
|
|
169
|
-
},
|
|
170
|
-
edges: [],
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
id: "node-inquiry",
|
|
174
|
-
name: "Handle Inquiry",
|
|
175
|
-
type: "conversation",
|
|
176
|
-
instruction: {
|
|
177
|
-
type: "prompt",
|
|
178
|
-
text: "file://./nodes/inquiry_abc123.md",
|
|
179
|
-
},
|
|
180
|
-
edges: [],
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
},
|
|
184
|
-
null,
|
|
185
|
-
2,
|
|
186
|
-
),
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
await Bun.write(
|
|
190
|
-
path.join(tmpDir, agentDir, "global_prompt.md"),
|
|
191
|
-
`---
|
|
192
|
-
version: 1
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
You are a professional receptionist.
|
|
196
|
-
|
|
197
|
-
Always be polite and helpful.
|
|
198
|
-
`,
|
|
199
|
-
)
|
|
200
|
-
|
|
201
|
-
await Bun.write(
|
|
202
|
-
path.join(tmpDir, agentDir, "nodes", "inquiry_abc123.md"),
|
|
203
|
-
`---
|
|
204
|
-
nodeId: "node-inquiry"
|
|
205
|
-
name: "Handle Inquiry"
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
Answer the caller's question to the best of your ability.
|
|
209
|
-
|
|
210
|
-
If you don't know, offer to transfer them.
|
|
211
|
-
`,
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
// Commit the files
|
|
215
|
-
await $`git add .`.quiet()
|
|
216
|
-
await $`git commit -m "Add flow agent"`.quiet()
|
|
217
|
-
const { stdout } = await $`git rev-parse HEAD`.quiet()
|
|
218
|
-
const commitHash = stdout.toString().trim()
|
|
219
|
-
|
|
220
|
-
// Create .sync.json
|
|
221
|
-
await Bun.write(
|
|
222
|
-
path.join(tmpDir, ".sync.json"),
|
|
223
|
-
JSON.stringify({ baseline: { commitHash } }, null, 2),
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
// Run getBaselineState
|
|
227
|
-
const result = await getBaselineState({ agentsDir })
|
|
228
|
-
|
|
229
|
-
// Verify results
|
|
230
|
-
expect(result.voiceAgents).toHaveLength(1)
|
|
231
|
-
expect(result.llms).toHaveLength(0)
|
|
232
|
-
expect(result.conversationFlows).toHaveLength(1)
|
|
233
|
-
|
|
234
|
-
const agent = result.voiceAgents[0]!
|
|
235
|
-
expect(agent.agent_name).toBe("Test Flow Agent")
|
|
236
|
-
expect(agent.response_engine.type).toBe("conversation-flow")
|
|
237
|
-
|
|
238
|
-
const flow = result.conversationFlows[0]!
|
|
239
|
-
// Global prompt placeholder should be resolved
|
|
240
|
-
expect(flow.global_prompt).toContain("You are a professional receptionist.")
|
|
241
|
-
expect(flow.global_prompt).toContain("Always be polite and helpful.")
|
|
242
|
-
expect(flow.global_prompt).not.toContain("version: 1")
|
|
243
|
-
|
|
244
|
-
// Node instruction placeholder should be resolved
|
|
245
|
-
const inquiryNode = flow.nodes?.find((n) => n.id === "node-inquiry")
|
|
246
|
-
expect(inquiryNode).toBeDefined()
|
|
247
|
-
expect(
|
|
248
|
-
inquiryNode?.type === "conversation" && inquiryNode.instruction.text,
|
|
249
|
-
).toContain("Answer the caller's question")
|
|
250
|
-
expect(
|
|
251
|
-
inquiryNode?.type === "conversation" && inquiryNode.instruction.text,
|
|
252
|
-
).toContain("offer to transfer them")
|
|
253
|
-
// Frontmatter should be stripped from node
|
|
254
|
-
expect(
|
|
255
|
-
inquiryNode?.type === "conversation" && inquiryNode.instruction.text,
|
|
256
|
-
).not.toContain("nodeId")
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
test("handles multiple agents of different types", async () => {
|
|
260
|
-
const agentsDir = "agents"
|
|
261
|
-
|
|
262
|
-
// Create LLM agent
|
|
263
|
-
const llmAgentDir = `${agentsDir}/llm_agent_111111`
|
|
264
|
-
await fs.mkdir(path.join(tmpDir, llmAgentDir), { recursive: true })
|
|
265
|
-
await Bun.write(
|
|
266
|
-
path.join(tmpDir, llmAgentDir, ".agent.json"),
|
|
267
|
-
JSON.stringify({
|
|
268
|
-
id: "agent_llm_1",
|
|
269
|
-
version: 1,
|
|
270
|
-
responseEngineVersion: 1,
|
|
271
|
-
}),
|
|
272
|
-
)
|
|
273
|
-
await Bun.write(
|
|
274
|
-
path.join(tmpDir, llmAgentDir, "config.json"),
|
|
275
|
-
JSON.stringify({
|
|
276
|
-
agent_name: "LLM Agent",
|
|
277
|
-
response_engine: { type: "retell-llm", llm_id: "llm_1", version: 1 },
|
|
278
|
-
}),
|
|
279
|
-
)
|
|
280
|
-
await Bun.write(
|
|
281
|
-
path.join(tmpDir, llmAgentDir, "llm.json"),
|
|
282
|
-
JSON.stringify({ model: "gpt-4" }),
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
// Create Flow agent
|
|
286
|
-
const flowAgentDir = `${agentsDir}/flow_agent_222222`
|
|
287
|
-
await fs.mkdir(path.join(tmpDir, flowAgentDir), { recursive: true })
|
|
288
|
-
await Bun.write(
|
|
289
|
-
path.join(tmpDir, flowAgentDir, ".agent.json"),
|
|
290
|
-
JSON.stringify({
|
|
291
|
-
id: "agent_flow_1",
|
|
292
|
-
version: 1,
|
|
293
|
-
responseEngineVersion: 1,
|
|
294
|
-
}),
|
|
295
|
-
)
|
|
296
|
-
await Bun.write(
|
|
297
|
-
path.join(tmpDir, flowAgentDir, "config.json"),
|
|
298
|
-
JSON.stringify({
|
|
299
|
-
agent_name: "Flow Agent",
|
|
300
|
-
response_engine: {
|
|
301
|
-
type: "conversation-flow",
|
|
302
|
-
conversation_flow_id: "flow_1",
|
|
303
|
-
version: 1,
|
|
304
|
-
},
|
|
305
|
-
}),
|
|
306
|
-
)
|
|
307
|
-
await Bun.write(
|
|
308
|
-
path.join(tmpDir, flowAgentDir, "conversation-flow.json"),
|
|
309
|
-
JSON.stringify({ nodes: [] }),
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
// Commit
|
|
313
|
-
await $`git add .`.quiet()
|
|
314
|
-
await $`git commit -m "Add multiple agents"`.quiet()
|
|
315
|
-
const { stdout } = await $`git rev-parse HEAD`.quiet()
|
|
316
|
-
const commitHash = stdout.toString().trim()
|
|
317
|
-
|
|
318
|
-
await Bun.write(
|
|
319
|
-
path.join(tmpDir, ".sync.json"),
|
|
320
|
-
JSON.stringify({ baseline: { commitHash } }),
|
|
321
|
-
)
|
|
322
|
-
|
|
323
|
-
const result = await getBaselineState({ agentsDir })
|
|
324
|
-
|
|
325
|
-
expect(result.voiceAgents).toHaveLength(2)
|
|
326
|
-
expect(result.llms).toHaveLength(1)
|
|
327
|
-
expect(result.conversationFlows).toHaveLength(1)
|
|
328
|
-
|
|
329
|
-
const agentNames = result.voiceAgents.map((a) => a.agent_name).sort()
|
|
330
|
-
expect(agentNames).toEqual(["Flow Agent", "LLM Agent"])
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
test("reads from specific git commit, not working directory", async () => {
|
|
334
|
-
const agentsDir = "agents"
|
|
335
|
-
const agentDir = `${agentsDir}/versioned_agent_xyz789`
|
|
336
|
-
|
|
337
|
-
// Create initial version
|
|
338
|
-
await fs.mkdir(path.join(tmpDir, agentDir), { recursive: true })
|
|
339
|
-
await Bun.write(
|
|
340
|
-
path.join(tmpDir, agentDir, ".agent.json"),
|
|
341
|
-
JSON.stringify({
|
|
342
|
-
id: "agent_versioned",
|
|
343
|
-
version: 1,
|
|
344
|
-
responseEngineVersion: 1,
|
|
345
|
-
}),
|
|
346
|
-
)
|
|
347
|
-
await Bun.write(
|
|
348
|
-
path.join(tmpDir, agentDir, "config.json"),
|
|
349
|
-
JSON.stringify({
|
|
350
|
-
agent_name: "Original Name",
|
|
351
|
-
response_engine: { type: "retell-llm", llm_id: "llm_v", version: 1 },
|
|
352
|
-
}),
|
|
353
|
-
)
|
|
354
|
-
await Bun.write(
|
|
355
|
-
path.join(tmpDir, agentDir, "llm.json"),
|
|
356
|
-
JSON.stringify({ model: "gpt-3.5" }),
|
|
357
|
-
)
|
|
358
|
-
|
|
359
|
-
// Commit v1
|
|
360
|
-
await $`git add .`.quiet()
|
|
361
|
-
await $`git commit -m "v1"`.quiet()
|
|
362
|
-
const { stdout } = await $`git rev-parse HEAD`.quiet()
|
|
363
|
-
const v1CommitHash = stdout.toString().trim()
|
|
364
|
-
|
|
365
|
-
// Modify files (v2 - not committed or committed separately)
|
|
366
|
-
await Bun.write(
|
|
367
|
-
path.join(tmpDir, agentDir, "config.json"),
|
|
368
|
-
JSON.stringify({
|
|
369
|
-
agent_name: "Updated Name",
|
|
370
|
-
response_engine: { type: "retell-llm", llm_id: "llm_v", version: 1 },
|
|
371
|
-
}),
|
|
372
|
-
)
|
|
373
|
-
await Bun.write(
|
|
374
|
-
path.join(tmpDir, agentDir, "llm.json"),
|
|
375
|
-
JSON.stringify({ model: "gpt-4" }),
|
|
376
|
-
)
|
|
377
|
-
await $`git add .`.quiet()
|
|
378
|
-
await $`git commit -m "v2"`.quiet()
|
|
379
|
-
|
|
380
|
-
// Point .sync.json to v1 commit
|
|
381
|
-
await Bun.write(
|
|
382
|
-
path.join(tmpDir, ".sync.json"),
|
|
383
|
-
JSON.stringify({ baseline: { commitHash: v1CommitHash } }),
|
|
384
|
-
)
|
|
385
|
-
|
|
386
|
-
const result = await getBaselineState({ agentsDir })
|
|
387
|
-
|
|
388
|
-
// Should get v1 data, not v2
|
|
389
|
-
expect(result.voiceAgents[0]!.agent_name).toBe("Original Name")
|
|
390
|
-
expect(result.llms[0]!.model as string).toBe("gpt-3.5")
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
test("throws error when .sync.json is missing", async () => {
|
|
394
|
-
const agentsDir = "agents"
|
|
395
|
-
|
|
396
|
-
await expect(getBaselineState({ agentsDir })).rejects.toThrow(
|
|
397
|
-
".sync.json file not found",
|
|
398
|
-
)
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
test("skips directories without .agent.json file", async () => {
|
|
402
|
-
const agentsDir = "agents"
|
|
403
|
-
|
|
404
|
-
// Create valid agent
|
|
405
|
-
const validDir = `${agentsDir}/valid_agent_aaa111`
|
|
406
|
-
await fs.mkdir(path.join(tmpDir, validDir), { recursive: true })
|
|
407
|
-
await Bun.write(
|
|
408
|
-
path.join(tmpDir, validDir, ".agent.json"),
|
|
409
|
-
JSON.stringify({
|
|
410
|
-
id: "agent_valid",
|
|
411
|
-
version: 1,
|
|
412
|
-
responseEngineVersion: 1,
|
|
413
|
-
}),
|
|
414
|
-
)
|
|
415
|
-
await Bun.write(
|
|
416
|
-
path.join(tmpDir, validDir, "config.json"),
|
|
417
|
-
JSON.stringify({
|
|
418
|
-
agent_name: "Valid Agent",
|
|
419
|
-
response_engine: { type: "retell-llm", llm_id: "llm_v", version: 1 },
|
|
420
|
-
}),
|
|
421
|
-
)
|
|
422
|
-
await Bun.write(
|
|
423
|
-
path.join(tmpDir, validDir, "llm.json"),
|
|
424
|
-
JSON.stringify({ model: "gpt-4" }),
|
|
425
|
-
)
|
|
426
|
-
|
|
427
|
-
// Create directory without .agent.json (should be skipped)
|
|
428
|
-
const invalidDir = `${agentsDir}/not_an_agent`
|
|
429
|
-
await fs.mkdir(path.join(tmpDir, invalidDir), { recursive: true })
|
|
430
|
-
await Bun.write(
|
|
431
|
-
path.join(tmpDir, invalidDir, "config.json"),
|
|
432
|
-
JSON.stringify({ agent_name: "Invalid" }),
|
|
433
|
-
)
|
|
434
|
-
|
|
435
|
-
await $`git add .`.quiet()
|
|
436
|
-
await $`git commit -m "mixed dirs"`.quiet()
|
|
437
|
-
const { stdout } = await $`git rev-parse HEAD`.quiet()
|
|
438
|
-
const commitHash = stdout.toString().trim()
|
|
439
|
-
|
|
440
|
-
await Bun.write(
|
|
441
|
-
path.join(tmpDir, ".sync.json"),
|
|
442
|
-
JSON.stringify({ baseline: { commitHash } }),
|
|
443
|
-
)
|
|
444
|
-
|
|
445
|
-
const result = await getBaselineState({ agentsDir })
|
|
446
|
-
|
|
447
|
-
expect(result.voiceAgents).toHaveLength(1)
|
|
448
|
-
expect(result.voiceAgents[0]!.agent_name).toBe("Valid Agent")
|
|
449
|
-
})
|
|
450
|
-
})
|