flowjet 2.1.0__tar.gz → 2.1.2__tar.gz
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.
- {flowjet-2.1.0 → flowjet-2.1.2}/CHANGELOG.md +32 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/PKG-INFO +2 -3
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/RFC-005-arcbox-tool-sandbox.md +7 -2
- {flowjet-2.1.0 → flowjet-2.1.2}/pyproject.toml +2 -5
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/SKILL.md +1 -1
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/stream.py +17 -4
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/workspace.py +109 -20
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/sandbox/arbox.py +40 -9
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/acp/agent.py +18 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/.gitignore +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/LICENSE +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/README.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/config/nano-local.yml +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/config/nano-sandbox-soothe.yml +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/config/nano.yml +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/deploy/README.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/completion-design.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/impl/IG-001-openai-compatible-server.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/impl/IG-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/impl/IG-003-production-isolation-hardening.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/RFC-001-openai-compatible-api.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/RFC-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/RFC-003-production-isolation-hardening.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/RFC-004-unified-package.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/rfc-history.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/rfc-index.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/docs/specs/rfc-namings.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/examples/README.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/__main__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/README.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/gws-drive/SKILL.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/gws-drive-upload/SKILL.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/.env.example +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/README.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/background_library.html +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/assets/showcase_template.html +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/background_styles.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/design_patterns.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/references/webgl_backgrounds.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/generate_showcase.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/scripts/svg_to_png.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/SKILL.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/brainstorming/spec-document-reviewer-prompt.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/coding-plan-template.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/impl-guide-template.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/pr-review-template.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/review/review-checklist.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/rfc-template.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-architecture-design.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-conceptual-design.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-impl-interface-design.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-drafts-readme.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-impl-readme.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-platonic.yml +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-history.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-index.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-namings.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-standard.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/BRAINSTORM/brainstorm.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-code.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-create-guide.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-full.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-update-guide.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-validate-guide.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-plan-modular-specs.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-architecture.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-conceptual.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-impl-interface.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scaffold.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scan.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REVIEW/review-spec-compliance.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-compliance.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-taxonomy.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-history.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-index.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-namings.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-refine.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-validate-consistency.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-overview.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-1.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-2.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-3.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/SKILL.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-deep.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-first.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/idea-first.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/paper-pipeline.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rigor-first.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/stance-first.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/systematic-review.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/verify-loop.json +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-ars-omr.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-omr-ars.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/csljson_to_omr.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/scripts/papers_index_to_csljson.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/__main__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/agent.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/cli.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/completion/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/completion/context.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/completion/engine.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/doctor_cmd.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/doctor_fix_cmd.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/progress.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/serve_cmd.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/setup_cmd.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/shell/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/shell/_fj.zsh +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/shell/fj.bash +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/threads.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/cli/tool_stream.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/_warnings.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/config.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/factory.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/skills.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/wiring.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/agent/workspace.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/backend_config.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/base.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/adapter.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/backend.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/nano/mapping.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/adapter.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/bridges/soothe/backend.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/events.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/identity.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/modes.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/protocol.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/direct.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/fake.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/adapter.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/admission.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/backend.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/errors.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/mode_gate.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/pool.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/runtime/isolation/request.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/sandbox/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/sandbox/resolver.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/sandbox/settings.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/streaming/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/streaming/presentation.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/streaming/tool_results.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/core/streaming/tool_stream.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/home.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/__main__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/acp/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/acp/routes.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/config.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/http/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/http/app.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/http/auth.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/__init__.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/errors.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/projection.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/routes.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/schemas.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/service.py +0 -0
- {flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/server/openai_compat/store.py +0 -0
|
@@ -10,6 +10,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [2.1.2] — 2026-10-21
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Bump `soothe` to 1.2.1.** The runtime dependency floor moves from
|
|
18
|
+
`>=1.2.0` to `>=1.2.1,<2.0.0` to track the upstream fix release. No flowjet
|
|
19
|
+
API or behavior changes; the locked dependency set is otherwise unchanged.
|
|
20
|
+
|
|
21
|
+
## [2.1.1] — 2026-10-21
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **ACP clarification turns no longer end empty.** When the agent paused with
|
|
26
|
+
`ask_user` questions over ACP, the questions were only surfaced as an
|
|
27
|
+
intermediate agent thought — but hosts accumulate message chunks as the
|
|
28
|
+
turn's reply, so a clarification turn ended with no content at all. The ACP
|
|
29
|
+
agent now also emits the questions block as a message chunk (rendered via
|
|
30
|
+
`format_questions_block`), so the user sees the questions in the host's reply
|
|
31
|
+
surface and answers there.
|
|
32
|
+
|
|
33
|
+
- **`format_questions_block` supports non-CLI hosts.** The resume footer
|
|
34
|
+
("Resume with: fjf -t <thread> <your answer>") was hardcoded for the CLI.
|
|
35
|
+
ACP and other non-CLI hosts now pass `resume_hint=""` to omit the
|
|
36
|
+
CLI-specific footer; the user answers in the host's own input surface.
|
|
37
|
+
The CLI path is unchanged (footer still shown by default).
|
|
38
|
+
|
|
39
|
+
- **Drop the direct `arcbox` dependency from the `server` extra.** The arcbox
|
|
40
|
+
SDK ships transitively via soothe-nano (a dependency of soothe), so the
|
|
41
|
+
explicit `arcbox>=0.1.0` pin in `pyproject.toml` was redundant and could
|
|
42
|
+
drift out of sync. The sandbox import error message is updated to point at
|
|
43
|
+
the transitive path instead of instructing `pip install arcbox`.
|
|
44
|
+
|
|
13
45
|
## [2.1.0] — 2026-10-18
|
|
14
46
|
|
|
15
47
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flowjet
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by Soothe
|
|
5
5
|
Project-URL: Homepage, https://github.com/caesar0301/flowjet
|
|
6
6
|
Project-URL: Repository, https://github.com/caesar0301/flowjet
|
|
@@ -22,7 +22,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
22
22
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
23
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
24
|
Requires-Python: <3.15,>=3.11
|
|
25
|
-
Requires-Dist: soothe<2.0.0,>=1.2.
|
|
25
|
+
Requires-Dist: soothe<2.0.0,>=1.2.1
|
|
26
26
|
Provides-Extra: dev
|
|
27
27
|
Requires-Dist: httpx>=0.27.0; extra == 'dev'
|
|
28
28
|
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
@@ -34,7 +34,6 @@ Requires-Dist: ruff>=0.12.0; extra == 'dev'
|
|
|
34
34
|
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
35
35
|
Provides-Extra: server
|
|
36
36
|
Requires-Dist: agent-client-protocol[http]<1.0.0,>=0.12.1; extra == 'server'
|
|
37
|
-
Requires-Dist: arcbox>=0.1.0; extra == 'server'
|
|
38
37
|
Requires-Dist: fastapi>=0.115.0; extra == 'server'
|
|
39
38
|
Requires-Dist: langchain-core>=0.3; extra == 'server'
|
|
40
39
|
Requires-Dist: pydantic-settings>=2.0; extra == 'server'
|
|
@@ -38,11 +38,16 @@ microVM duplicated soothe-nano's sandbox capability at the wrong layer.
|
|
|
38
38
|
- Per-session guest isolation: the sandbox is **per workspace**. Concurrent
|
|
39
39
|
sessions sharing one workspace share one guest (staged serially; a peer
|
|
40
40
|
mid-run skips the host push so live guest state is never clobbered).
|
|
41
|
-
- Guest-side deletion propagation: a host file deleted between sessions is
|
|
42
|
-
not removed from the guest (the pull direction is authoritative at close).
|
|
43
41
|
- Incremental (delta) transfers: staging is a full-tree push/pull with a
|
|
44
42
|
`(size, mtime_ns)` manifest skip for unchanged files.
|
|
45
43
|
|
|
44
|
+
> **Revision (2026-10-21, RFC-RD-607)**: guest-side deletion propagation is no
|
|
45
|
+
> longer a non-goal — `pull` now removes host files that were recorded in the
|
|
46
|
+
> last push manifest but disappeared from the guest tree (so agent-side
|
|
47
|
+
> deletes flow guest → host → sync checkpoint → content tree). Host files
|
|
48
|
+
> created after the push are never in the manifest and can never be deleted
|
|
49
|
+
> by this path.
|
|
50
|
+
|
|
46
51
|
## 4. Configuration
|
|
47
52
|
|
|
48
53
|
Enabled by a `sandbox:` section in the flowjet nano.yml. Flowjet owns the
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flowjet"
|
|
7
|
-
version = "2.1.
|
|
7
|
+
version = "2.1.2"
|
|
8
8
|
description = "FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by Soothe"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -27,7 +27,7 @@ classifiers = [
|
|
|
27
27
|
]
|
|
28
28
|
# Single-dependency CLI wheel; HTTP service deps live in the `server` extra.
|
|
29
29
|
dependencies = [
|
|
30
|
-
"soothe>=1.2.
|
|
30
|
+
"soothe>=1.2.1,<2.0.0",
|
|
31
31
|
]
|
|
32
32
|
|
|
33
33
|
[project.optional-dependencies]
|
|
@@ -40,9 +40,6 @@ server = [
|
|
|
40
40
|
"langchain-core>=0.3",
|
|
41
41
|
# S3/MinIO workspace sync backend
|
|
42
42
|
"s3fs>=2024.6",
|
|
43
|
-
# ArcBox microVM SDK — sandboxed tool execution via soothe's
|
|
44
|
-
# sandbox backend (https://github.com/arcboxlabs/arcbox)
|
|
45
|
-
"arcbox>=0.1.0",
|
|
46
43
|
]
|
|
47
44
|
dev = [
|
|
48
45
|
"pytest>=8.0.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: logo-generator
|
|
2
|
+
name: logo-generator-skill
|
|
3
3
|
description: >
|
|
4
4
|
Generate professional SVG logos and high-end showcase images. Use when the user wants to: (1) Create a logo or icon for their product/brand, (2) Generate logo design concepts based on product information, (3) Create professional logo showcase presentations with multiple background styles, (4) Export logos in various formats (SVG, PNG), or (5) Iterate on logo designs with different visual styles. Supports geometric patterns, dot matrix designs, line systems, and mixed compositions. Generates showcase images using Nano Banana (Gemini image generation) with 12 professional background styles.
|
|
5
5
|
---
|
|
@@ -276,16 +276,28 @@ class AnswerWriter:
|
|
|
276
276
|
return self.buf
|
|
277
277
|
|
|
278
278
|
|
|
279
|
-
def format_questions_block(
|
|
279
|
+
def format_questions_block(
|
|
280
|
+
questions: tuple[dict[str, Any], ...],
|
|
281
|
+
thread_id: str,
|
|
282
|
+
resume_hint: str | None = None,
|
|
283
|
+
) -> str:
|
|
280
284
|
"""Render ``ask_user`` questions as a terminal block with a resume hint.
|
|
281
285
|
|
|
282
286
|
The block is written to stdout after the ephemeral progress line is
|
|
283
287
|
cleared, so it stays visible. Each question lists its options with the
|
|
284
288
|
recommended one (label ending in "(Recommended)") marked. The footer
|
|
285
|
-
tells the user how to resume with an answer via ``fjf``.
|
|
289
|
+
tells the user how to resume with an answer via ``fjf``. Non-CLI hosts
|
|
290
|
+
(ACP) pass ``resume_hint=""`` to omit the CLI-specific footer — the user
|
|
291
|
+
answers in the host's own input.
|
|
286
292
|
"""
|
|
293
|
+
footer = (
|
|
294
|
+
f"Resume with: fjf -t {thread_id} <your answer>" if resume_hint is None else resume_hint
|
|
295
|
+
)
|
|
287
296
|
if not questions:
|
|
288
|
-
|
|
297
|
+
block = "\n⏸ Paused for input"
|
|
298
|
+
if footer:
|
|
299
|
+
block += f" · {footer}"
|
|
300
|
+
return block + "\n"
|
|
289
301
|
lines: list[str] = ["", "⏸ Paused for input:"]
|
|
290
302
|
for qi, q in enumerate(questions, 1):
|
|
291
303
|
header = str(q.get("header") or "").strip()
|
|
@@ -310,7 +322,8 @@ def format_questions_block(questions: tuple[dict[str, Any], ...], thread_id: str
|
|
|
310
322
|
lines.append(f" • {label}{marker} — {desc}")
|
|
311
323
|
else:
|
|
312
324
|
lines.append(f" • {label}{marker}")
|
|
313
|
-
|
|
325
|
+
if footer:
|
|
326
|
+
lines.append(f"\n {footer}\n")
|
|
314
327
|
return "\n".join(lines) + "\n"
|
|
315
328
|
|
|
316
329
|
|
|
@@ -7,6 +7,7 @@ import hashlib
|
|
|
7
7
|
import logging
|
|
8
8
|
import re
|
|
9
9
|
import shutil
|
|
10
|
+
from dataclasses import dataclass
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any
|
|
12
13
|
|
|
@@ -110,6 +111,29 @@ class WorkspaceResolver:
|
|
|
110
111
|
return path == self._home
|
|
111
112
|
|
|
112
113
|
|
|
114
|
+
@dataclass
|
|
115
|
+
class _OpenWorkspaceEntry:
|
|
116
|
+
"""One open workspace — shared by all concurrent turns of the same run_id.
|
|
117
|
+
|
|
118
|
+
``active_runs`` counts turns currently mid-run on this workspace; the
|
|
119
|
+
lifecycle (``manager.close``) belongs to the last run out. ``manifest``
|
|
120
|
+
caches the recovered engine manifest so the per-turn refresh can protect
|
|
121
|
+
agent artifacts from deletion reconcile.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
ws: Any
|
|
125
|
+
active_runs: int = 0
|
|
126
|
+
manifest: Any | None = None
|
|
127
|
+
restored: bool = False
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _manifest_artifact_paths(manifest: Any | None) -> list[str]:
|
|
131
|
+
"""Relative paths of the manifest's artifacts (reconcile protection set)."""
|
|
132
|
+
if manifest is None:
|
|
133
|
+
return []
|
|
134
|
+
return [entry.path for entry in (getattr(manifest, "artifacts", None) or [])]
|
|
135
|
+
|
|
136
|
+
|
|
113
137
|
class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
114
138
|
"""Workspace resolver backed by soothe's fsspec workspace sync.
|
|
115
139
|
|
|
@@ -150,7 +174,7 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
150
174
|
self._manager: Any | None = None
|
|
151
175
|
self._sync_backend: Any | None = None
|
|
152
176
|
self._restore_cas: Any | None = None
|
|
153
|
-
self._open_workspaces: dict[str,
|
|
177
|
+
self._open_workspaces: dict[str, _OpenWorkspaceEntry] = {}
|
|
154
178
|
|
|
155
179
|
@property
|
|
156
180
|
def is_sync_enabled(self) -> bool:
|
|
@@ -263,7 +287,17 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
263
287
|
return path
|
|
264
288
|
|
|
265
289
|
async def open_session(self, session: str, workspace: Path) -> None:
|
|
266
|
-
"""
|
|
290
|
+
"""Refresh the workspace from the object store + start dirty tracking.
|
|
291
|
+
|
|
292
|
+
RFC-RD-607 §4.3: the sync boundary is the agent turn (one pair of
|
|
293
|
+
open/close hooks per prompt). Every turn unconditionally materializes
|
|
294
|
+
the content tree — including the reuse path where a peer session's
|
|
295
|
+
turn already holds the workspace open (sha-skip keeps repeat turns
|
|
296
|
+
cheap). Deletion reconcile runs only while this turn is the sole
|
|
297
|
+
active run on the workspace: deleting files under a peer's feet is
|
|
298
|
+
worse than a delayed delete, so peer-occupied turns skip it (logged).
|
|
299
|
+
Prior agent artifacts are restored once, on the opening turn.
|
|
300
|
+
"""
|
|
267
301
|
manager = self._ensure_manager()
|
|
268
302
|
if manager is None:
|
|
269
303
|
return
|
|
@@ -273,18 +307,39 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
273
307
|
# for perfect consistency across resolve/open/close.
|
|
274
308
|
run_id = workspace.name
|
|
275
309
|
|
|
276
|
-
|
|
277
|
-
if
|
|
278
|
-
|
|
310
|
+
entry = self._open_workspaces.get(run_id)
|
|
311
|
+
if entry is None:
|
|
312
|
+
ws = await manager.open(run_id)
|
|
313
|
+
entry = _OpenWorkspaceEntry(ws=ws)
|
|
314
|
+
self._open_workspaces[run_id] = entry
|
|
315
|
+
else:
|
|
316
|
+
ws = entry.ws
|
|
317
|
+
entry.active_runs += 1
|
|
318
|
+
|
|
319
|
+
if entry.manifest is None:
|
|
320
|
+
try:
|
|
321
|
+
entry.manifest = await self._recover_manifest(ws)
|
|
322
|
+
except Exception:
|
|
323
|
+
logger.warning("Manifest recovery failed for run %s", run_id, exc_info=True)
|
|
279
324
|
|
|
280
|
-
ws = await manager.open(run_id)
|
|
281
325
|
# Dual-source sync, read path: materialize the content root (e.g.
|
|
282
326
|
# triarch workspace materials) into the workspace BEFORE replaying
|
|
283
327
|
# checkpoint state, so the agent sees both its prior outputs and the
|
|
284
|
-
# latest backend-uploaded files.
|
|
328
|
+
# latest backend-uploaded files. The dirty tracker only watches
|
|
329
|
+
# input/working/output + root files, so content-tree writes never
|
|
330
|
+
# pollute the dirty set.
|
|
285
331
|
if hasattr(ws, "materialize_content"):
|
|
286
332
|
try:
|
|
287
|
-
|
|
333
|
+
if self._supports_content_reconcile(ws):
|
|
334
|
+
await ws.materialize_content(
|
|
335
|
+
protected=_manifest_artifact_paths(entry.manifest),
|
|
336
|
+
reconcile=entry.active_runs == 1,
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
# soothe < 2.0: no protected/reconcile kwargs — degrade to
|
|
340
|
+
# a plain materialize (no reconcile; deletes stay until
|
|
341
|
+
# the soothe 2.0.0 release train lands).
|
|
342
|
+
await ws.materialize_content()
|
|
288
343
|
except Exception:
|
|
289
344
|
logger.warning(
|
|
290
345
|
"Content materialization failed for run %s; continuing with "
|
|
@@ -292,19 +347,43 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
292
347
|
run_id,
|
|
293
348
|
exc_info=True,
|
|
294
349
|
)
|
|
295
|
-
|
|
296
|
-
|
|
350
|
+
|
|
351
|
+
if entry.manifest is not None and not entry.restored:
|
|
352
|
+
await self._restore_prior_state(ws, entry.manifest)
|
|
353
|
+
entry.restored = True
|
|
297
354
|
|
|
298
355
|
# Start dirty tracking + background uploader for incremental persistence.
|
|
299
356
|
await ws.start_tracking()
|
|
300
357
|
logger.info("Opened sync workspace for session %s at %s", session, workspace)
|
|
301
358
|
|
|
302
|
-
|
|
303
|
-
|
|
359
|
+
@staticmethod
|
|
360
|
+
def _supports_content_reconcile(ws: Any) -> bool:
|
|
361
|
+
"""True when the workspace's ``materialize_content`` takes RFC-RD-607 kwargs.
|
|
362
|
+
|
|
363
|
+
soothe < 2.0 lacks ``protected``/``reconcile``; probing the signature
|
|
364
|
+
keeps flowjet runnable against both release trains.
|
|
365
|
+
"""
|
|
366
|
+
import inspect
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
params = inspect.signature(ws.materialize_content).parameters
|
|
370
|
+
except (TypeError, ValueError):
|
|
371
|
+
return False
|
|
372
|
+
return "protected" in params and "reconcile" in params
|
|
373
|
+
|
|
374
|
+
async def _recover_manifest(self, ws: Any) -> Any | None:
|
|
375
|
+
"""Recover the prior engine manifest snapshot (single call per open).
|
|
304
376
|
|
|
305
377
|
Round-trip half of workspace sync: ``close_session`` checkpoints and
|
|
306
|
-
uploads dirty files; this
|
|
307
|
-
|
|
378
|
+
uploads dirty files; this reads back the manifest so the per-turn
|
|
379
|
+
materialize can protect agent artifacts and the opening turn can
|
|
380
|
+
restore them.
|
|
381
|
+
"""
|
|
382
|
+
payload = await ws.recover() # reads the latest checkpoint payload
|
|
383
|
+
return payload.manifest_snapshot if payload is not None else None
|
|
384
|
+
|
|
385
|
+
async def _restore_prior_state(self, ws: Any, manifest: Any | None) -> None:
|
|
386
|
+
"""Materialize the recovered manifest's files locally.
|
|
308
387
|
|
|
309
388
|
- Agent-written files live in ``manifest.artifacts`` (path → sha256,
|
|
310
389
|
blobs under ``<root>/blobs/``) and are restored in place at their
|
|
@@ -312,8 +391,6 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
312
391
|
- Declared input resources (``manifest.resources``) are materialized
|
|
313
392
|
under ``<root>/input/`` via the soothe Materializer.
|
|
314
393
|
"""
|
|
315
|
-
payload = await ws.recover() # restores checkpoint state, returns snapshot payload
|
|
316
|
-
manifest = payload.manifest_snapshot if payload is not None else None
|
|
317
394
|
if manifest is None:
|
|
318
395
|
return
|
|
319
396
|
|
|
@@ -363,20 +440,32 @@ class SyncAwareWorkspaceResolver(WorkspaceResolver):
|
|
|
363
440
|
return self._restore_cas
|
|
364
441
|
|
|
365
442
|
async def close_session(self, session: str, workspace: Path) -> None:
|
|
366
|
-
"""Checkpoint dirty files + upload to object store
|
|
443
|
+
"""Checkpoint dirty files + upload to object store; close when last run ends.
|
|
444
|
+
|
|
445
|
+
Concurrent turns of the same workspace share one open workspace:
|
|
446
|
+
a mid-run peer's close checkpoints the shared state but keeps the
|
|
447
|
+
workspace open — the lifecycle (``manager.close``) belongs to the
|
|
448
|
+
last run out (RFC-RD-607 §4.3).
|
|
449
|
+
"""
|
|
367
450
|
if self._manager is None:
|
|
368
451
|
return
|
|
369
452
|
|
|
370
453
|
run_id = workspace.name
|
|
371
454
|
|
|
372
|
-
|
|
373
|
-
if
|
|
455
|
+
entry = self._open_workspaces.get(run_id)
|
|
456
|
+
if entry is None:
|
|
374
457
|
return
|
|
375
458
|
|
|
459
|
+
if entry.active_runs > 0:
|
|
460
|
+
entry.active_runs -= 1
|
|
376
461
|
try:
|
|
377
|
-
await ws.checkpoint()
|
|
462
|
+
await entry.ws.checkpoint()
|
|
378
463
|
except Exception:
|
|
379
464
|
logger.warning("Checkpoint failed for session %s", session, exc_info=True)
|
|
465
|
+
if entry.active_runs > 0:
|
|
466
|
+
return
|
|
467
|
+
|
|
468
|
+
self._open_workspaces.pop(run_id, None)
|
|
380
469
|
try:
|
|
381
470
|
await self._manager.close(run_id)
|
|
382
471
|
except Exception:
|
|
@@ -26,12 +26,10 @@ def _import_arcbox() -> Any:
|
|
|
26
26
|
import arcbox # type: ignore[import-not-found]
|
|
27
27
|
except ImportError as exc: # pragma: no cover - environment-dependent
|
|
28
28
|
raise RuntimeError(
|
|
29
|
-
"sandbox.enabled=true in nano.yml requires the
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"(Linux). Remove the sandbox: section or set sandbox.enabled=false "
|
|
34
|
-
"to run tools host-side."
|
|
29
|
+
"sandbox.enabled=true in nano.yml requires the arcbox SDK, which ships "
|
|
30
|
+
"transitively via soothe-nano (a dependency of soothe). Reinstall flowjet "
|
|
31
|
+
"or run `arcbox serve` on the host. Remove the sandbox: section or set "
|
|
32
|
+
"sandbox.enabled=false to run tools host-side."
|
|
35
33
|
) from exc
|
|
36
34
|
return arcbox
|
|
37
35
|
|
|
@@ -118,12 +116,18 @@ class WorkspaceStager:
|
|
|
118
116
|
) -> dict[str, tuple[int, int]]:
|
|
119
117
|
"""Download the guest workspace tree back to the host (skip identical).
|
|
120
118
|
|
|
121
|
-
|
|
119
|
+
Deletion propagation (RFC-RD-607 §4.4): files the agent deleted inside
|
|
120
|
+
the guest are absent from its tree and are removed from the host too.
|
|
121
|
+
Only paths recorded in the push manifest are eligible — host files
|
|
122
|
+
created after the push are never in it, so they can never be deleted
|
|
123
|
+
by this path. Returns the manifest for the next push.
|
|
122
124
|
"""
|
|
123
125
|
root = Path(workspace)
|
|
124
126
|
guest_root = PurePosixPath(self._settings.workspace_root)
|
|
125
127
|
pulled = 0
|
|
128
|
+
deleted = 0
|
|
126
129
|
next_manifest: dict[str, tuple[int, int]] = {}
|
|
130
|
+
guest_files: set[str] = set()
|
|
127
131
|
|
|
128
132
|
async def walk(guest_dir: PurePosixPath, rel_dir: PurePosixPath) -> None:
|
|
129
133
|
nonlocal pulled
|
|
@@ -144,6 +148,7 @@ class WorkspaceStager:
|
|
|
144
148
|
continue
|
|
145
149
|
if entry.kind != "file":
|
|
146
150
|
continue
|
|
151
|
+
guest_files.add(rel_entry.as_posix())
|
|
147
152
|
data = await sandbox.files.read_bytes(guest_path)
|
|
148
153
|
dest = root / Path(*rel_entry.parts)
|
|
149
154
|
if dest.is_file():
|
|
@@ -159,8 +164,34 @@ class WorkspaceStager:
|
|
|
159
164
|
pulled += 1
|
|
160
165
|
|
|
161
166
|
await walk(guest_root, PurePosixPath("."))
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
for rel in manifest:
|
|
168
|
+
if rel in guest_files:
|
|
169
|
+
continue
|
|
170
|
+
dest = root / Path(*PurePosixPath(rel).parts)
|
|
171
|
+
if not dest.is_file() or dest.is_symlink():
|
|
172
|
+
continue
|
|
173
|
+
try:
|
|
174
|
+
await asyncio.to_thread(dest.unlink)
|
|
175
|
+
except OSError:
|
|
176
|
+
logger.warning("Sandbox pull: host delete failed for %s in %s", rel, workspace)
|
|
177
|
+
continue
|
|
178
|
+
deleted += 1
|
|
179
|
+
parent = dest.parent
|
|
180
|
+
while parent != root and parent.is_relative_to(root):
|
|
181
|
+
if any(parent.iterdir()):
|
|
182
|
+
break
|
|
183
|
+
try:
|
|
184
|
+
parent.rmdir()
|
|
185
|
+
except OSError:
|
|
186
|
+
break
|
|
187
|
+
parent = parent.parent
|
|
188
|
+
if pulled or deleted:
|
|
189
|
+
logger.info(
|
|
190
|
+
"Sandbox pull for %s: %d files pulled, %d guest deletions propagated",
|
|
191
|
+
workspace,
|
|
192
|
+
pulled,
|
|
193
|
+
deleted,
|
|
194
|
+
)
|
|
164
195
|
return next_manifest
|
|
165
196
|
|
|
166
197
|
|
|
@@ -462,6 +462,24 @@ class FlowJetAcpAgent:
|
|
|
462
462
|
session_id,
|
|
463
463
|
update_agent_thought_text(event.message or "Waiting for input"),
|
|
464
464
|
)
|
|
465
|
+
# Surface the ask_user questions as message chunks, not
|
|
466
|
+
# just a thought: hosts accumulate message chunks as the
|
|
467
|
+
# turn's reply, so a clarification turn would otherwise
|
|
468
|
+
# end with no content at all (thoughts are intermediate
|
|
469
|
+
# narration). The CLI renders the same block.
|
|
470
|
+
if event.questions:
|
|
471
|
+
from flowjet.cli.stream import format_questions_block
|
|
472
|
+
|
|
473
|
+
block = format_questions_block(
|
|
474
|
+
event.questions,
|
|
475
|
+
session_id,
|
|
476
|
+
resume_hint="",
|
|
477
|
+
)
|
|
478
|
+
await client.session_update(
|
|
479
|
+
session_id,
|
|
480
|
+
update_agent_message_text(block),
|
|
481
|
+
)
|
|
482
|
+
output_text += block
|
|
465
483
|
elif isinstance(event, RunCompleted):
|
|
466
484
|
output_text = event.output_text or output_text
|
|
467
485
|
usage_info = event.usage
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/.env.example
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json
RENAMED
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.1.0 → flowjet-2.1.2}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|