Skip to content

Commit 09667c1

Browse files
RoyLinRoyLin
authored andcommitted
fix(python-sdk): fix Py<PyAny>: Clone in PySessionOptions for cross-platform builds
- Remove #[derive(Clone)] from PySessionOptions (contains PyObject fields) - Add manual Clone impl using clone_ref(py) via Python::with_gil - Fix get_memory_store/session_store/security_provider getters to take py arg - Extract session_store kind from with_gil closure to avoid E0382 borrow error - Add --locked flag to maturin build in publish-python.yml
1 parent 828c79f commit 09667c1

2 files changed

Lines changed: 50 additions & 11 deletions

File tree

.github/workflows/publish-python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868
uses: PyO3/maturin-action@v1
6969
with:
7070
target: ${{ matrix.settings.target }}
71-
args: --release --out dist --manifest-path sdk/python/Cargo.toml -i python3.10 -i python3.11 -i python3.12 -i python3.13
71+
args: --release --locked --out dist --manifest-path sdk/python/Cargo.toml -i python3.10 -i python3.11 -i python3.12 -i python3.13
7272
manylinux: ${{ matrix.settings.manylinux || 'auto' }}
7373

7474
- name: Upload artifact

sdk/python/src/lib.rs

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,6 @@ impl PyDefaultSecurityProvider {
19031903
///
19041904
/// Pass to `agent.session(workspace, options)` to override defaults.
19051905
#[pyclass(name = "SessionOptions")]
1906-
#[derive(Clone)]
19071906
struct PySessionOptions {
19081907
model: Option<String>,
19091908
builtin_skills: bool,
@@ -1949,6 +1948,31 @@ struct PySessionOptions {
19491948
auto_save: bool,
19501949
}
19511950

1951+
impl Clone for PySessionOptions {
1952+
fn clone(&self) -> Self {
1953+
pyo3::Python::with_gil(|py| Self {
1954+
model: self.model.clone(),
1955+
builtin_skills: self.builtin_skills,
1956+
skill_dirs: self.skill_dirs.clone(),
1957+
agent_dirs: self.agent_dirs.clone(),
1958+
queue_config: self.queue_config.clone(),
1959+
auto_compact: self.auto_compact,
1960+
auto_compact_threshold: self.auto_compact_threshold,
1961+
memory_store: self.memory_store.as_ref().map(|o| o.clone_ref(py)),
1962+
session_store: self.session_store.as_ref().map(|o| o.clone_ref(py)),
1963+
security_provider: self.security_provider.as_ref().map(|o| o.clone_ref(py)),
1964+
role: self.role.clone(),
1965+
guidelines: self.guidelines.clone(),
1966+
response_style: self.response_style.clone(),
1967+
extra: self.extra.clone(),
1968+
inline_skills: self.inline_skills.clone(),
1969+
max_tool_rounds: self.max_tool_rounds,
1970+
session_id: self.session_id.clone(),
1971+
auto_save: self.auto_save,
1972+
})
1973+
}
1974+
}
1975+
19521976
#[pymethods]
19531977
impl PySessionOptions {
19541978
#[new]
@@ -2060,8 +2084,8 @@ impl PySessionOptions {
20602084
///
20612085
/// opts.memory_store = FileMemoryStore('./memory')
20622086
#[getter]
2063-
fn get_memory_store(&self) -> Option<pyo3::PyObject> {
2064-
self.memory_store.clone()
2087+
fn get_memory_store(&self, py: pyo3::Python<'_>) -> Option<pyo3::PyObject> {
2088+
self.memory_store.as_ref().map(|o| o.clone_ref(py))
20652089
}
20662090

20672091
#[setter]
@@ -2078,8 +2102,8 @@ impl PySessionOptions {
20782102
/// opts.session_store = FileSessionStore('./sessions') # persists to disk
20792103
/// opts.session_store = MemorySessionStore() # ephemeral
20802104
#[getter]
2081-
fn get_session_store(&self) -> Option<pyo3::PyObject> {
2082-
self.session_store.clone()
2105+
fn get_session_store(&self, py: pyo3::Python<'_>) -> Option<pyo3::PyObject> {
2106+
self.session_store.as_ref().map(|o| o.clone_ref(py))
20832107
}
20842108

20852109
#[setter]
@@ -2095,8 +2119,8 @@ impl PySessionOptions {
20952119
///
20962120
/// opts.security_provider = DefaultSecurityProvider()
20972121
#[getter]
2098-
fn get_security_provider(&self) -> Option<pyo3::PyObject> {
2099-
self.security_provider.clone()
2122+
fn get_security_provider(&self, py: pyo3::Python<'_>) -> Option<pyo3::PyObject> {
2123+
self.security_provider.as_ref().map(|o| o.clone_ref(py))
21002124
}
21012125

21022126
#[setter]
@@ -2479,15 +2503,30 @@ fn build_rust_session_options(so: PySessionOptions) -> RustSessionOptions {
24792503
}
24802504
}
24812505
if let Some(ref store) = so.session_store {
2482-
Python::with_gil(|py| {
2506+
enum SessionStoreKind {
2507+
File(String),
2508+
Memory,
2509+
}
2510+
let kind = Python::with_gil(|py| {
24832511
if let Ok(file_store) = store.extract::<pyo3::PyRef<PyFileSessionStore>>(py) {
2484-
o = o.with_file_session_store(file_store.dir.clone());
2512+
Some(SessionStoreKind::File(file_store.dir.clone()))
24852513
} else if store.extract::<pyo3::PyRef<PyMemorySessionStore>>(py).is_ok() {
2514+
Some(SessionStoreKind::Memory)
2515+
} else {
2516+
None
2517+
}
2518+
});
2519+
match kind {
2520+
Some(SessionStoreKind::File(dir)) => {
2521+
o = o.with_file_session_store(dir);
2522+
}
2523+
Some(SessionStoreKind::Memory) => {
24862524
let s: Arc<dyn a3s_code_core::store::SessionStore> =
24872525
Arc::new(a3s_code_core::store::MemorySessionStore::new());
24882526
o = o.with_session_store(s);
24892527
}
2490-
});
2528+
None => {}
2529+
}
24912530
}
24922531
if let Some(ref sec) = so.security_provider {
24932532
let is_default =

0 commit comments

Comments
 (0)