Skip to content

Commit ed0182b

Browse files
authored
Add config dir to session options (#15)
* Add config dir to session options * add tests * Use join
1 parent a4ffbf0 commit ed0182b

File tree

13 files changed

+117
-2
lines changed

13 files changed

+117
-2
lines changed

dotnet/src/Client.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig? config = nul
343343
config?.OnPermissionRequest != null ? true : null,
344344
config?.Streaming == true ? true : null,
345345
config?.McpServers,
346-
config?.CustomAgents);
346+
config?.CustomAgents,
347+
config?.ConfigDir);
347348

348349
var response = await connection.Rpc.InvokeWithCancellationAsync<CreateSessionResponse>(
349350
"session.create", [request], cancellationToken);
@@ -925,7 +926,8 @@ private record CreateSessionRequest(
925926
bool? RequestPermission,
926927
bool? Streaming,
927928
Dictionary<string, object>? McpServers,
928-
List<CustomAgentConfig>? CustomAgents);
929+
List<CustomAgentConfig>? CustomAgents,
930+
string? ConfigDir);
929931

930932
private record ToolDefinition(
931933
string Name,

dotnet/src/Types.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ public class SessionConfig
293293
{
294294
public string? SessionId { get; set; }
295295
public string? Model { get; set; }
296+
297+
/// <summary>
298+
/// Override the default configuration directory location.
299+
/// When specified, the session will use this directory for storing config and state.
300+
/// </summary>
301+
public string? ConfigDir { get; set; }
302+
296303
public ICollection<AIFunction>? Tools { get; set; }
297304
public SystemMessageConfig? SystemMessage { get; set; }
298305
public List<string>? AvailableTools { get; set; }

dotnet/test/SessionTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,4 +380,19 @@ public async Task SendAndWait_Throws_On_Timeout()
380380

381381
Assert.Contains("timed out", ex.Message);
382382
}
383+
384+
[Fact]
385+
public async Task Should_Create_Session_With_Custom_Config_Dir()
386+
{
387+
var customConfigDir = Path.Join(Ctx.HomeDir, "custom-config");
388+
var session = await Client.CreateSessionAsync(new SessionConfig { ConfigDir = customConfigDir });
389+
390+
Assert.Matches(@"^[a-f0-9-]+$", session.SessionId);
391+
392+
// Session should work normally with custom config dir
393+
await session.SendAsync(new MessageOptions { Prompt = "What is 1+1?" });
394+
var assistantMessage = await TestHelper.GetFinalAssistantMessageAsync(session);
395+
Assert.NotNull(assistantMessage);
396+
Assert.Contains("2", assistantMessage!.Data.Content);
397+
}
383398
}

go/client.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,10 @@ func (c *Client) CreateSession(config *SessionConfig) (*Session, error) {
532532
}
533533
params["customAgents"] = customAgents
534534
}
535+
// Add config directory override
536+
if config.ConfigDir != "" {
537+
params["configDir"] = config.ConfigDir
538+
}
535539
}
536540

537541
result, err := c.client.Request("session.create", params)

go/e2e/session_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,38 @@ func TestSession(t *testing.T) {
718718
t.Errorf("Expected assistant message to contain '300', got %v", assistantMessage.Data.Content)
719719
}
720720
})
721+
722+
t.Run("should create session with custom config dir", func(t *testing.T) {
723+
ctx.ConfigureForTest(t)
724+
725+
customConfigDir := ctx.HomeDir + "/custom-config"
726+
session, err := client.CreateSession(&copilot.SessionConfig{
727+
ConfigDir: customConfigDir,
728+
})
729+
if err != nil {
730+
t.Fatalf("Failed to create session with custom config dir: %v", err)
731+
}
732+
733+
matched, _ := regexp.MatchString(`^[a-f0-9-]+$`, session.SessionID)
734+
if !matched {
735+
t.Errorf("Expected session ID to match UUID pattern, got %q", session.SessionID)
736+
}
737+
738+
// Session should work normally with custom config dir
739+
_, err = session.Send(copilot.MessageOptions{Prompt: "What is 1+1?"})
740+
if err != nil {
741+
t.Fatalf("Failed to send message: %v", err)
742+
}
743+
744+
assistantMessage, err := testharness.GetFinalAssistantMessage(session, 60*time.Second)
745+
if err != nil {
746+
t.Fatalf("Failed to get assistant message: %v", err)
747+
}
748+
749+
if assistantMessage.Data.Content == nil || !strings.Contains(*assistantMessage.Data.Content, "2") {
750+
t.Errorf("Expected assistant message to contain '2', got %v", assistantMessage.Data.Content)
751+
}
752+
})
721753
}
722754

723755
func getSystemMessage(exchange testharness.ParsedHttpExchange) string {

go/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ type SessionConfig struct {
138138
SessionID string
139139
// Model to use for this session
140140
Model string
141+
// ConfigDir overrides the default configuration directory location.
142+
// When specified, the session will use this directory for storing config and state.
143+
ConfigDir string
141144
// Tools exposes caller-implemented tools to the CLI
142145
Tools []Tool
143146
// SystemMessage configures system message customization

nodejs/src/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ export class CopilotClient {
446446
streaming: config.streaming,
447447
mcpServers: config.mcpServers,
448448
customAgents: config.customAgents,
449+
configDir: config.configDir,
449450
});
450451

451452
const sessionId = (response as { sessionId: string }).sessionId;

nodejs/src/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,12 @@ export interface SessionConfig {
324324
*/
325325
model?: string;
326326

327+
/**
328+
* Override the default configuration directory location.
329+
* When specified, the session will use this directory for storing config and state.
330+
*/
331+
configDir?: string;
332+
327333
/**
328334
* Tools exposed to the CLI server
329335
*/

nodejs/test/e2e/session.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,20 @@ describe("Sessions", async () => {
321321
// Verify the assistant response contains the expected answer
322322
expect(assistantMessage?.data.content).toContain("300");
323323
});
324+
325+
it("should create session with custom config dir", async () => {
326+
const customConfigDir = `${homeDir}/custom-config`;
327+
const session = await client.createSession({
328+
configDir: customConfigDir,
329+
});
330+
331+
expect(session.sessionId).toMatch(/^[a-f0-9-]+$/);
332+
333+
// Session should work normally with custom config dir
334+
await session.send({ prompt: "What is 1+1?" });
335+
const assistantMessage = await getFinalAssistantMessage(session);
336+
expect(assistantMessage.data.content).toContain("2");
337+
});
324338
});
325339

326340
function getSystemMessage(exchange: ParsedHttpExchange): string | undefined {

python/copilot/client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,11 @@ async def create_session(self, config: Optional[SessionConfig] = None) -> Copilo
400400
self._convert_custom_agent_to_wire_format(agent) for agent in custom_agents
401401
]
402402

403+
# Add config directory override if provided
404+
config_dir = cfg.get("config_dir")
405+
if config_dir:
406+
payload["configDir"] = config_dir
407+
403408
if not self._client:
404409
raise RuntimeError("Client not connected")
405410
response = await self._client.request("session.create", payload)

0 commit comments

Comments
 (0)