microsoft / microsoft/agent-framework

Python: Harness: session-scoped file_access_store option when session_id is unknown at create_harness_agent time

Open
#8,539 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

python triage
Dominant language
Python
Stars
13.6k
Forks
2.3k
Avg merge
2d 45m
Merged PRs (30d)
358

Description

## Summary

`create_harness_agent`'s `file_access_store` today expects the caller to supply an `AgentFileStore` whose root is **already** the desired working directory. Unlike `FileMemoryProvider`, `FileAccessProvider` does **not** isolate by `session_id` at run time.

In hosts that compile/create the harness agent **before** an `AgentSession` exists (AG-UI / multi-turn entrypoints, workflow executors restored later from checkpoint, etc.), the caller cannot honestly put `session_id` into the store root at `create_harness_agent` time. Platforms end up inventing workarounds (provisional root + mutating `_root_path` on first run), which is fragile and outside the public API.

Please add a first-class option so **file access can be session-scoped inside the framework**, with the store root derived from `session_id` when the session becomes available—not by asking the caller to bake `session_id` into the path at create time.

## Current behavior

| Provider | Store root at create | Isolation |
|----------|----------------------|-----------|
| `FileMemoryProvider` (`file_memory_store`) | Shared root (default `{cwd}/agent-file-memory`) | Framework derives a working folder from `session_id` / `scope` at run time |
| `FileAccessProvider` (`file_access_store`) | Caller-supplied root is the working area | **No** session nesting; docs say the store “should already be scoped to the desired folder” |

Relevant docs in `FileAccessProvider`:

> Unlike MemoryContextProvider / FileMemoryProvider … FileAccessProvider operates on a shared, persistent store … The store is passed in by the caller and should already be scoped to the desired folder or storage location.

`create_harness_agent` wiring:

- `file_memory_store=None` → default shared FS store; provider isolates per session.
- `file_access_store=...` → opt-in shared tools; **no** equivalent session isolation.

## Problem

Call sites often look like:

1. Build / compile harness agent (tools, providers, middleware).
2. Later: `agent.run(..., session=AgentSession(...))` — **this** is when `session_id` is known (or assigned by the framework).

Requiring `FileSystemAgentFileStore(f".../{session_id}")` at step 1 forces one of:

- Shared root for all sessions (loses isolation),
- Recreate the whole harness agent once `session_id` is known (expensive / awkward with middleware & pools),
- Host-side hacks that mutate private store fields after create.

`FileMemoryProvider` already solved the “unknown session at create time” case for memory; file access needs the same class of solution if hosts want per-session workspaces (downloads, shell-adjacent artifacts, user uploads, etc.).

## Proposed direction (API sketch — open to better shapes)

Add an opt-in session-scoped mode for file access that keeps create-time API free of `session_id`, for example:

```python
create_harness_agent(
client,
# Option A: base directory; framework creates `{base}/{session_key}/` at run time
file_access_base_dir=Path(".../workspaces"),
file_access_session_scoped=True, # default False to preserve today's shared semantics
)

# or Option B: factory invoked when SessionContext has session_id
create_harness_agent(
client,
file_access_store_factory=lambda session_id: FileSystemAgentFileStore(base / session_id),
)
```

Expectations:

1. **Create time**: no `session_id` required.
2. **Run time**: on `before_run` / first use, framework resolves `session_id` (same rules as file memory: require a session, treat id as opaque key via `_storage_key_segment` or equivalent).
3. **Root for tools**: the effective `FileAccessProvider` store root **is** that session directory (paths relative to it), not `base/` with a manual `{session_id}/...` prefix the model must know about.
4. **Default remains shared**: existing `file_access_store=...` behavior unchanged for backward compatibility.
5. Optionally align with `file_memory`: allow a shared parent root + framework-owned session subfolder, rather than forcing hosts to pre-bake the session path.

## Alternatives considered

- Keep requiring hosts to pass a session-rooted store → doesn't work when session is created inside `run` / AG-UI / checkpoint restore.
- Recreate agent per session → works but is heavy and duplicates wiring.
- Host mutates `FileSystemAgentFileStore._root_path` after create → works today as a private workaround; should not be the recommended pattern.

## Environment

- Package: `agent-framework` (Python harness: `create_harness_agent`, `FileAccessProvider`, `FileMemoryProvider`)
- Motivation: multi-request hosts that compile agents once per HTTP/SSE request (or once per workflow graph) before the framework `AgentSession.session_id` is available.

Thanks!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the create_harness_agent entry point and trace how FileAccessProvider and FileMemoryProvider receive and resolve their stores. Compare the session handling and storage-key rules, then determine where a session-scoped file-access option can be introduced without changing the default shared behavior. Done means the selected API works when session_id is unavailable at creation time, scopes tool paths to the resolved session directory, and has coverage for shared and session-scoped modes.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.