Skip to content

Commit d6117c0

Browse files
committed
sdk: make cwd truly optional
1 parent 2c45678 commit d6117c0

File tree

2 files changed

+58
-33
lines changed

2 files changed

+58
-33
lines changed

sdk/src/run-state.ts

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ function deriveKnowledgeFiles(
145145
}
146146

147147
export async function initialSessionState(
148-
cwd: string,
148+
cwd: string | undefined,
149149
options: {
150150
projectFiles?: Record<string, string>
151151
knowledgeFiles?: Record<string, string>
@@ -157,28 +157,34 @@ export async function initialSessionState(
157157
let { projectFiles, agentDefinitions = [] } = options
158158
let { knowledgeFiles } = options
159159

160-
// Auto-discover project files if not provided
161-
if (projectFiles === undefined) {
160+
// Auto-discover project files if not provided and cwd is available
161+
if (projectFiles === undefined && cwd) {
162162
projectFiles = discoverProjectFiles(cwd)
163163
}
164164
if (knowledgeFiles === undefined) {
165-
knowledgeFiles = deriveKnowledgeFiles(projectFiles)
165+
knowledgeFiles = projectFiles ? deriveKnowledgeFiles(projectFiles) : {}
166166
}
167167

168168
const processedAgentTemplates = processAgentDefinitions(agentDefinitions)
169169
const processedCustomToolDefinitions = processCustomToolDefinitions(
170170
options.customToolDefinitions ?? [],
171171
)
172172

173-
// Generate file tree and token scores from projectFiles
174-
const { fileTree, fileTokenScores, tokenCallers } = await computeProjectIndex(
175-
cwd,
176-
projectFiles,
177-
)
173+
// Generate file tree and token scores from projectFiles if available
174+
let fileTree: FileTreeNode[] = []
175+
let fileTokenScores: Record<string, any> = {}
176+
let tokenCallers: Record<string, any> = {}
177+
178+
if (cwd && projectFiles) {
179+
const result = await computeProjectIndex(cwd, projectFiles)
180+
fileTree = result.fileTree
181+
fileTokenScores = result.fileTokenScores
182+
tokenCallers = result.tokenCallers
183+
}
178184

179185
const initialState = getInitialSessionState({
180-
projectRoot: cwd,
181-
cwd,
186+
projectRoot: cwd ?? process.cwd(),
187+
cwd: cwd ?? process.cwd(),
182188
fileTree,
183189
fileTokenScores,
184190
tokenCallers,
@@ -276,7 +282,7 @@ export function withMessageHistory({
276282
* even when continuing from a previous run.
277283
*/
278284
export async function applyOverridesToSessionState(
279-
cwd: string,
285+
cwd: string | undefined,
280286
baseSessionState: SessionState,
281287
overrides: {
282288
projectFiles?: Record<string, string>
@@ -298,11 +304,18 @@ export async function applyOverridesToSessionState(
298304

299305
// Apply projectFiles override (recomputes file tree and token scores)
300306
if (overrides.projectFiles !== undefined) {
301-
const { fileTree, fileTokenScores, tokenCallers } =
302-
await computeProjectIndex(cwd, overrides.projectFiles)
303-
sessionState.fileContext.fileTree = fileTree
304-
sessionState.fileContext.fileTokenScores = fileTokenScores
305-
sessionState.fileContext.tokenCallers = tokenCallers
307+
if (cwd) {
308+
const { fileTree, fileTokenScores, tokenCallers } =
309+
await computeProjectIndex(cwd, overrides.projectFiles)
310+
sessionState.fileContext.fileTree = fileTree
311+
sessionState.fileContext.fileTokenScores = fileTokenScores
312+
sessionState.fileContext.tokenCallers = tokenCallers
313+
} else {
314+
// If projectFiles are provided but no cwd, reset file context fields
315+
sessionState.fileContext.fileTree = []
316+
sessionState.fileContext.fileTokenScores = {}
317+
sessionState.fileContext.tokenCallers = {}
318+
}
306319

307320
// Auto-derive knowledgeFiles if not explicitly provided
308321
if (overrides.knowledgeFiles === undefined) {

sdk/src/run.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export async function run({
7373
apiKey,
7474
fingerprintId,
7575

76-
cwd = process.cwd(),
76+
cwd,
7777
projectFiles,
7878
knowledgeFiles,
7979
agentDefinitions,
@@ -118,7 +118,11 @@ export async function run({
118118
onError({ message: error.message })
119119
},
120120
readFiles: ({ filePaths }) =>
121-
readFiles({ filePaths, override: overrideTools?.read_files, cwd }),
121+
readFiles({
122+
filePaths,
123+
override: overrideTools?.read_files,
124+
cwd,
125+
}),
122126
handleToolCall: (action) =>
123127
handleToolCall({
124128
action,
@@ -207,23 +211,30 @@ export async function run({
207211
return result
208212
}
209213

214+
function requireCwd(cwd: string | undefined, toolName: string): string {
215+
if (!cwd) {
216+
throw new Error(
217+
`cwd is required for the ${toolName} tool. Please provide cwd in CodebuffClientOptions or override the ${toolName} tool.`,
218+
)
219+
}
220+
return cwd
221+
}
222+
210223
async function readFiles({
211224
filePaths,
212225
override,
213226
cwd,
214-
}: { filePaths: string[] } & (
215-
| {
216-
override: NonNullable<
217-
Required<CodebuffClientOptions>['overrideTools']['read_files']
218-
>
219-
cwd?: string
220-
}
221-
| { override: undefined; cwd: string }
222-
)) {
227+
}: {
228+
filePaths: string[]
229+
override?: NonNullable<
230+
Required<CodebuffClientOptions>['overrideTools']['read_files']
231+
>
232+
cwd?: string
233+
}) {
223234
if (override) {
224235
return await override({ filePaths })
225236
}
226-
return getFiles(filePaths, cwd)
237+
return getFiles(filePaths, requireCwd(cwd, 'read_files'))
227238
}
228239

229240
async function handleToolCall({
@@ -235,7 +246,7 @@ async function handleToolCall({
235246
action: ServerAction<'tool-call-request'>
236247
overrides: NonNullable<CodebuffClientOptions['overrideTools']>
237248
customToolDefinitions: Record<string, CustomToolDefinition>
238-
cwd: string
249+
cwd?: string
239250
}): ReturnType<WebSocketHandler['handleToolCall']> {
240251
const toolName = action.toolName
241252
const input = action.input
@@ -267,15 +278,16 @@ async function handleToolCall({
267278
} else if (toolName === 'end_turn') {
268279
result = []
269280
} else if (toolName === 'write_file' || toolName === 'str_replace') {
270-
result = changeFile(input, cwd)
281+
result = changeFile(input, requireCwd(cwd, toolName))
271282
} else if (toolName === 'run_terminal_command') {
283+
const resolvedCwd = requireCwd(cwd, 'run_terminal_command')
272284
result = await runTerminalCommand({
273285
...input,
274-
cwd: path.resolve(cwd, input.cwd ?? '.'),
286+
cwd: path.resolve(resolvedCwd, input.cwd ?? '.'),
275287
} as Parameters<typeof runTerminalCommand>[0])
276288
} else if (toolName === 'code_search') {
277289
result = await codeSearch({
278-
projectPath: cwd,
290+
projectPath: requireCwd(cwd, 'code_search'),
279291
...input,
280292
} as Parameters<typeof codeSearch>[0])
281293
} else if (toolName === 'run_file_change_hooks') {

0 commit comments

Comments
 (0)