flowjet 2.0.7__tar.gz → 2.0.9__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.0.7 → flowjet-2.0.9}/CHANGELOG.md +31 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/PKG-INFO +1 -1
- {flowjet-2.0.7 → flowjet-2.0.9}/pyproject.toml +1 -1
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/cli.py +62 -1
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/stream.py +72 -3
- flowjet-2.0.9/src/flowjet/core/_warnings.py +53 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/direct.py +1 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/bridges/nano/backend.py +1 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/bridges/nano/mapping.py +63 -4
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/events.py +13 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/__main__.py +6 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/.gitignore +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/LICENSE +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/config/nano.yml +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/deploy/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/deploy/nano.yml +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/completion-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/drafts/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/drafts/api-spec.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/impl/IG-001-openai-compatible-server.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/impl/IG-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/impl/IG-003-production-isolation-hardening.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/impl/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/impl/TEST-COVERAGE-MATRIX.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/naming.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/server.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/RFC-001-openai-compatible-api.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/RFC-002-isolated-thread-pool-runtime.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/RFC-003-production-isolation-hardening.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/RFC-004-unified-package.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/rfc-history.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/rfc-index.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/rfc-namings.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/templates/architecture-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/templates/conceptual-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/templates/impl-interface-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/templates/rfc-standard.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/specs/templates/rfc-template.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/docs/upgrade.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/examples/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/nano.yml +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/__main__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/gws-drive/SKILL.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/gws-drive-upload/SKILL.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/.env.example +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/README.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/SKILL.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/assets/background_library.html +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/assets/showcase_template.html +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/references/background_styles.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/references/design_patterns.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/references/webgl_backgrounds.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/requirements.txt +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/scripts/generate_showcase.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/logo-generator-skill/scripts/svg_to_png.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/SKILL.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/brainstorming/spec-document-reviewer-prompt.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/coding-plan-template.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/implementation/impl-guide-template.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/review/pr-review-template.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/review/review-checklist.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/specs/rfc-template.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-architecture-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-conceptual-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/specs/template-impl-interface-design.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-drafts-readme.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-impl-readme.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-platonic.yml +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-history.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-index.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-namings.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/assets/templates/template-rfc-standard.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/BRAINSTORM/brainstorm.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-code.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-create-guide.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-full.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-update-guide.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/IMPL/impl-validate-guide.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-plan-modular-specs.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-architecture.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-conceptual.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-recover-impl-interface.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scaffold.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/INIT/init-scan.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/REFERENCE.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/REVIEW/review-spec-compliance.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-compliance.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-check-taxonomy.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-history.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-index.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-generate-namings.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-refine.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/SPECS/specs-validate-consistency.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-overview.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-1.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-2.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/platonic-coding/references/WORKFLOW/workflow-phase-3.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/SKILL.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-deep.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/evidence-first.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/idea-first.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/paper-pipeline.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/rapid.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/rigor-first.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/stance-first.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/systematic-review.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/verify-loop.json +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-ars-omr.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/references/handoff-omr-ars.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/references/routing.md +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/scripts/csljson_to_omr.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/scripts/papers_index_to_csljson.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/__main__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/agent.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/completion/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/completion/context.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/completion/engine.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/doctor_cmd.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/doctor_fix_cmd.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/progress.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/serve_cmd.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/setup_cmd.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/shell/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/shell/_fj.zsh +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/shell/fj.bash +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/threads.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/cli/tool_stream.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backend.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/fake.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/adapter.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/admission.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/backend.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/errors.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/mode_gate.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/pool.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/request.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/backends/isolation/workspace.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/bootstrap.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/bridges/nano/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/bridges/nano/adapter.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/identity.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/modes.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/protocol.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/tool_results.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/core/tool_stream.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/home.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/acp/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/acp/agent.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/acp/routes.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/config.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/http/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/http/app.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/http/auth.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/__init__.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/errors.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/projection.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/routes.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/schemas.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/service.py +0 -0
- {flowjet-2.0.7 → flowjet-2.0.9}/src/flowjet/server/openai_compat/store.py +0 -0
|
@@ -10,6 +10,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
10
10
|
|
|
11
11
|
## [Unreleased]
|
|
12
12
|
|
|
13
|
+
## [2.0.9] — 2026-09-24
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **Suppress noisy third-party warnings at startup.** `requests` emits
|
|
18
|
+
`RequestsDependencyWarning` when the installed `urllib3` / `chardet` /
|
|
19
|
+
`charset_normalizer` versions fall outside its supported range, and
|
|
20
|
+
`soothe`'s `TypeSafeClassifier` triggers LangChain's `LangChainBetaWarning`.
|
|
21
|
+
Both are version-mismatch or beta-API notices the user cannot act on, so
|
|
22
|
+
they are now silenced at the earliest point of each entry point. A new
|
|
23
|
+
`core/_warnings.py` module exposes `suppress_known_warnings()`, called from
|
|
24
|
+
both the CLI (`cli.py`) and server (`server/__main__.py`) `main()` before
|
|
25
|
+
the heavy agent stack is imported.
|
|
26
|
+
|
|
27
|
+
## [2.0.8] — 2026-09-24
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **`ask_user` interrupt/resume in the CLI.** The nano runtime now surfaces
|
|
32
|
+
soothe's `ask_user` interrupt so the agent can pause mid-run to ask
|
|
33
|
+
structured questions and resume on a follow-up invocation. `RunRequest`
|
|
34
|
+
gains `resume_value`, which the direct and nano backends forward into
|
|
35
|
+
LangGraph's `Command(resume=...)` instead of starting a new turn.
|
|
36
|
+
`mapping.py` extracts the `ask_user` questions and interrupt ids from a
|
|
37
|
+
`__interrupt__` payload and carries them on `InterruptWaiting`; `stream.py`
|
|
38
|
+
renders the questions block (options, recommended marker, resume hint) and
|
|
39
|
+
returns an `INTERRUPTED` sentinel instead of "Done" when the graph pauses.
|
|
40
|
+
`cli.py` detects a pending `ask_user` interrupt on the thread snapshot,
|
|
41
|
+
prints the questions, and feeds the user's query text as the resume answer
|
|
42
|
+
— so `fjf -t <thread> <answer>` continues the paused run.
|
|
43
|
+
|
|
13
44
|
## [2.0.7] — 2026-09-23
|
|
14
45
|
|
|
15
46
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: flowjet
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.9
|
|
4
4
|
Summary: FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by soothe-nano
|
|
5
5
|
Project-URL: Homepage, https://github.com/caesar0301/flowjet
|
|
6
6
|
Project-URL: Repository, https://github.com/caesar0301/flowjet
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "flowjet"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.9"
|
|
8
8
|
description = "FlowJet — agent CLI (fj) and server (ACP + OpenAI-compatible HTTP) powered by soothe-nano"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -518,6 +518,37 @@ def run_pin_thread(thread_id: str) -> int:
|
|
|
518
518
|
return 0
|
|
519
519
|
|
|
520
520
|
|
|
521
|
+
async def _detect_pending_interrupt(agent: Any, thread_id: str) -> Any:
|
|
522
|
+
"""Return the pending ``ask_user`` interrupt value, or ``None``.
|
|
523
|
+
|
|
524
|
+
Checks the LangGraph snapshot for the thread. When an ``ask_user``
|
|
525
|
+
interrupt is pending, its ``value`` carries the question specs; the CLI
|
|
526
|
+
can resume the run by feeding the user's answer to ``Command(resume=...)``.
|
|
527
|
+
"""
|
|
528
|
+
get_state = getattr(agent, "aget_state", None)
|
|
529
|
+
if not callable(get_state):
|
|
530
|
+
return None
|
|
531
|
+
try:
|
|
532
|
+
snapshot = await get_state({"configurable": {"thread_id": thread_id}})
|
|
533
|
+
except Exception:
|
|
534
|
+
return None
|
|
535
|
+
if snapshot is None:
|
|
536
|
+
return None
|
|
537
|
+
interrupts = getattr(snapshot, "interrupts", None) or ()
|
|
538
|
+
if not interrupts:
|
|
539
|
+
# Some snapshots nest interrupts under per-task state.
|
|
540
|
+
tasks = getattr(snapshot, "tasks", None) or ()
|
|
541
|
+
for task in tasks:
|
|
542
|
+
task_interrupts = getattr(task, "interrupts", None) or ()
|
|
543
|
+
interrupts = task_interrupts
|
|
544
|
+
break
|
|
545
|
+
for entry in interrupts:
|
|
546
|
+
value = getattr(entry, "value", None)
|
|
547
|
+
if isinstance(value, dict) and value.get("type") == "ask_user":
|
|
548
|
+
return value
|
|
549
|
+
return None
|
|
550
|
+
|
|
551
|
+
|
|
521
552
|
async def run_async(args: argparse.Namespace) -> int:
|
|
522
553
|
conflict = validate_arg_composition(args)
|
|
523
554
|
if conflict:
|
|
@@ -570,14 +601,39 @@ async def run_async(args: argparse.Namespace) -> int:
|
|
|
570
601
|
ask_mode=getattr(args, "ask", False),
|
|
571
602
|
bypass_mode=getattr(args, "bypass", False),
|
|
572
603
|
)
|
|
604
|
+
# If the thread paused on an ``ask_user`` interrupt, the user's
|
|
605
|
+
# query text is their answer — resume the run instead of
|
|
606
|
+
# starting a new turn. ``fjf`` (follow) hits this path when the
|
|
607
|
+
# previous run ended on a question.
|
|
608
|
+
resume_value: Any = None
|
|
609
|
+
pending = await _detect_pending_interrupt(agent, thread_id)
|
|
610
|
+
if pending is not None:
|
|
611
|
+
from flowjet.cli.stream import format_questions_block
|
|
612
|
+
|
|
613
|
+
questions = pending.get("questions") or ()
|
|
614
|
+
if isinstance(questions, list):
|
|
615
|
+
questions = tuple(q for q in questions if isinstance(q, dict))
|
|
616
|
+
else:
|
|
617
|
+
questions = ()
|
|
618
|
+
# Print the questions so the user sees what they're answering.
|
|
619
|
+
if questions:
|
|
620
|
+
sys.stdout.write(format_questions_block(questions, thread_id))
|
|
621
|
+
sys.stdout.flush()
|
|
622
|
+
resume_value = {"answers": [args.query_text]}
|
|
573
623
|
if args.no_stream:
|
|
574
|
-
await invoke_query(
|
|
624
|
+
await invoke_query(
|
|
625
|
+
agent,
|
|
626
|
+
args.query_text,
|
|
627
|
+
thread_id=thread_id,
|
|
628
|
+
resume_value=resume_value,
|
|
629
|
+
)
|
|
575
630
|
else:
|
|
576
631
|
await stream_query(
|
|
577
632
|
agent,
|
|
578
633
|
args.query_text,
|
|
579
634
|
thread_id=thread_id,
|
|
580
635
|
show_tool_calls=args.verbose,
|
|
636
|
+
resume_value=resume_value,
|
|
581
637
|
)
|
|
582
638
|
except ConcurrentSessionError as exc:
|
|
583
639
|
sys.stderr.write(f"error: {exc}\n")
|
|
@@ -661,6 +717,11 @@ def main_follow(argv: list[str] | None = None) -> int:
|
|
|
661
717
|
|
|
662
718
|
|
|
663
719
|
def main(argv: list[str] | None = None) -> int:
|
|
720
|
+
# Silence noisy third-party warnings (requests version-mismatch,
|
|
721
|
+
# LangChain beta-API) before any heavy import pulls them in.
|
|
722
|
+
from flowjet.core._warnings import suppress_known_warnings
|
|
723
|
+
|
|
724
|
+
suppress_known_warnings()
|
|
664
725
|
try:
|
|
665
726
|
# Parse first so ``-V`` / ``-h`` / ``--help`` exit before we touch the
|
|
666
727
|
# logging stack (and the heavy ``flowjet.cli.agent`` import it used to
|
|
@@ -36,6 +36,11 @@ from flowjet.core.tool_results import (
|
|
|
36
36
|
# Min interval between live narration previews on the progress line (seconds).
|
|
37
37
|
_STATUS_PREVIEW_MIN_INTERVAL = 0.12
|
|
38
38
|
|
|
39
|
+
# Returned by ``stream_query`` / ``invoke_query`` when the agent paused for
|
|
40
|
+
# human input (``ask_user`` interrupt) instead of completing. The CLI checks
|
|
41
|
+
# for this sentinel to print the resume hint and accept an answer via ``fjf``.
|
|
42
|
+
INTERRUPTED = "__FJ_INTERRUPTED__"
|
|
43
|
+
|
|
39
44
|
|
|
40
45
|
def _format_duration(seconds: float) -> str:
|
|
41
46
|
"""Format an elapsed time as a short human-readable duration.
|
|
@@ -273,6 +278,44 @@ class AnswerWriter:
|
|
|
273
278
|
return self.buf
|
|
274
279
|
|
|
275
280
|
|
|
281
|
+
def format_questions_block(questions: tuple[dict[str, Any], ...], thread_id: str) -> str:
|
|
282
|
+
"""Render ``ask_user`` questions as a terminal block with a resume hint.
|
|
283
|
+
|
|
284
|
+
The block is written to stdout after the ephemeral progress line is
|
|
285
|
+
cleared, so it stays visible. Each question lists its options with the
|
|
286
|
+
recommended one (label ending in "(Recommended)") marked. The footer
|
|
287
|
+
tells the user how to resume with an answer via ``fjf``.
|
|
288
|
+
"""
|
|
289
|
+
if not questions:
|
|
290
|
+
return f"\n⏸ Paused for input · resume with: fjf -t {thread_id} <your answer>\n"
|
|
291
|
+
lines: list[str] = ["", "⏸ Paused for input:"]
|
|
292
|
+
for qi, q in enumerate(questions, 1):
|
|
293
|
+
header = str(q.get("header") or "").strip()
|
|
294
|
+
question = str(q.get("question") or "").strip()
|
|
295
|
+
if len(questions) > 1:
|
|
296
|
+
prefix = f" Q{qi}: "
|
|
297
|
+
else:
|
|
298
|
+
prefix = " "
|
|
299
|
+
if header:
|
|
300
|
+
lines.append(f"{prefix}[{header}] {question}")
|
|
301
|
+
else:
|
|
302
|
+
lines.append(f"{prefix}{question}")
|
|
303
|
+
options = q.get("options")
|
|
304
|
+
if isinstance(options, list):
|
|
305
|
+
for opt in options:
|
|
306
|
+
if not isinstance(opt, dict):
|
|
307
|
+
continue
|
|
308
|
+
label = str(opt.get("label") or "").strip()
|
|
309
|
+
desc = str(opt.get("description") or "").strip()
|
|
310
|
+
marker = " ★" if "(Recommended)" in label or "Recommended" in label else ""
|
|
311
|
+
if desc:
|
|
312
|
+
lines.append(f" • {label}{marker} — {desc}")
|
|
313
|
+
else:
|
|
314
|
+
lines.append(f" • {label}{marker}")
|
|
315
|
+
lines.append(f"\n Resume with: fjf -t {thread_id} <your answer>\n")
|
|
316
|
+
return "\n".join(lines) + "\n"
|
|
317
|
+
|
|
318
|
+
|
|
276
319
|
async def stream_query(
|
|
277
320
|
agent: SootheNanoAgent,
|
|
278
321
|
query: str,
|
|
@@ -283,8 +326,14 @@ async def stream_query(
|
|
|
283
326
|
out: TextIO | None = None,
|
|
284
327
|
err: TextIO | None = None,
|
|
285
328
|
progress: ProgressLine | None = None,
|
|
329
|
+
resume_value: Any = None,
|
|
286
330
|
) -> str:
|
|
287
|
-
"""Run a query with ephemeral progress; print the complete final answer.
|
|
331
|
+
"""Run a query with ephemeral progress; print the complete final answer.
|
|
332
|
+
|
|
333
|
+
When the agent pauses for human input (``ask_user`` interrupt), the
|
|
334
|
+
questions are rendered and :data:`INTERRUPTED` is returned — the run is
|
|
335
|
+
not complete and must be resumed with ``fjf -t <thread> <answer>``.
|
|
336
|
+
"""
|
|
288
337
|
stdout = out or sys.stdout
|
|
289
338
|
stderr = err or sys.stderr
|
|
290
339
|
status = progress if progress is not None else ProgressLine(stdout)
|
|
@@ -293,6 +342,7 @@ async def stream_query(
|
|
|
293
342
|
# ``-v``: emit each tool call once when args are available.
|
|
294
343
|
mirrored_tool_ids: set[str] = set()
|
|
295
344
|
started_at = time.monotonic()
|
|
345
|
+
interrupted = False
|
|
296
346
|
|
|
297
347
|
# Deepagents emits a deprecation warning mid-run that would smash the
|
|
298
348
|
# ephemeral progress line when mixed onto the terminal.
|
|
@@ -309,7 +359,12 @@ async def stream_query(
|
|
|
309
359
|
async with status:
|
|
310
360
|
status.update("Thinking", color="cyan")
|
|
311
361
|
async for event in backend.stream_run(
|
|
312
|
-
RunRequest(
|
|
362
|
+
RunRequest(
|
|
363
|
+
model="default",
|
|
364
|
+
input_text=query,
|
|
365
|
+
session=thread_id,
|
|
366
|
+
resume_value=resume_value,
|
|
367
|
+
)
|
|
313
368
|
):
|
|
314
369
|
if isinstance(event, Progress):
|
|
315
370
|
# ``raw`` carries the soothe-nano custom payload so the
|
|
@@ -378,7 +433,15 @@ async def stream_query(
|
|
|
378
433
|
|
|
379
434
|
if isinstance(event, InterruptWaiting):
|
|
380
435
|
status.update("Waiting for input…", color="yellow")
|
|
381
|
-
if
|
|
436
|
+
if event.questions:
|
|
437
|
+
# A real ``ask_user`` interrupt pauses the graph —
|
|
438
|
+
# render the questions and mark the run as interrupted
|
|
439
|
+
# so the CLI returns ``INTERRUPTED`` instead of "Done".
|
|
440
|
+
status.blank()
|
|
441
|
+
stdout.write(format_questions_block(event.questions, thread_id))
|
|
442
|
+
stdout.flush()
|
|
443
|
+
interrupted = True
|
|
444
|
+
elif show_tool_calls:
|
|
382
445
|
_write_verbose(
|
|
383
446
|
status,
|
|
384
447
|
stderr,
|
|
@@ -390,6 +453,10 @@ async def stream_query(
|
|
|
390
453
|
raise RuntimeError(event.message)
|
|
391
454
|
|
|
392
455
|
answer_text = answer.finish()
|
|
456
|
+
if interrupted:
|
|
457
|
+
# The run paused for input — don't print "Done", the questions block
|
|
458
|
+
# (or generic pause message) is already on stdout.
|
|
459
|
+
return INTERRUPTED
|
|
393
460
|
duration = _format_duration(time.monotonic() - started_at)
|
|
394
461
|
stdout.write(f"\n✓ Done · {duration} · {thread_id}\n")
|
|
395
462
|
stdout.flush()
|
|
@@ -403,6 +470,7 @@ async def invoke_query(
|
|
|
403
470
|
thread_id: str,
|
|
404
471
|
out: TextIO | None = None,
|
|
405
472
|
progress: ProgressLine | None = None,
|
|
473
|
+
resume_value: Any = None,
|
|
406
474
|
) -> str:
|
|
407
475
|
"""Progress until done, then print the final text (no live narration preview)."""
|
|
408
476
|
return await stream_query(
|
|
@@ -413,4 +481,5 @@ async def invoke_query(
|
|
|
413
481
|
live_answer=False,
|
|
414
482
|
out=out,
|
|
415
483
|
progress=progress,
|
|
484
|
+
resume_value=resume_value,
|
|
416
485
|
)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Suppress noisy third-party warnings that are not actionable for users.
|
|
2
|
+
|
|
3
|
+
These warnings come from dependencies (``requests``, ``soothe``/``langchain``)
|
|
4
|
+
and fire at import time or agent build time. They are version-mismatch or
|
|
5
|
+
beta-API notices that the user cannot fix, so we silence them globally at the
|
|
6
|
+
earliest point of each entry point (CLI ``main`` and server ``main``).
|
|
7
|
+
|
|
8
|
+
Call :func:`suppress_known_warnings` before importing the heavy agent stack.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import warnings
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def suppress_known_warnings() -> None:
|
|
17
|
+
"""Silence dependency warnings that users cannot act on.
|
|
18
|
+
|
|
19
|
+
Safe to call multiple times — ``filterwarnings`` is idempotent for the
|
|
20
|
+
same rule.
|
|
21
|
+
|
|
22
|
+
Suppressed:
|
|
23
|
+
|
|
24
|
+
* ``RequestsDependencyWarning`` — ``requests`` emits this when the
|
|
25
|
+
installed ``urllib3`` / ``chardet`` / ``charset_normalizer`` versions
|
|
26
|
+
fall outside its supported range. The versions still work; the warning
|
|
27
|
+
is informational only.
|
|
28
|
+
* ``LangChainBetaWarning`` — ``soothe`` uses ``TypeSafeClassifier`` which
|
|
29
|
+
is a beta LangChain API. The API may change, but the warning is noise
|
|
30
|
+
for end users.
|
|
31
|
+
"""
|
|
32
|
+
# ``requests`` import-time version-mismatch warning.
|
|
33
|
+
warnings.filterwarnings(
|
|
34
|
+
"ignore",
|
|
35
|
+
category=UserWarning,
|
|
36
|
+
message=r".*urllib3 .* or chardet .* doesn't match a supported version.*",
|
|
37
|
+
)
|
|
38
|
+
# Also match by the concrete warning class when available — covers the
|
|
39
|
+
# exact ``RequestsDependencyWarning`` emitted by ``requests/__init__.py``.
|
|
40
|
+
try:
|
|
41
|
+
from requests.exceptions import RequestsDependencyWarning
|
|
42
|
+
|
|
43
|
+
warnings.filterwarnings("ignore", category=RequestsDependencyWarning)
|
|
44
|
+
except Exception: # pragma: no cover - requests not installed / API changed
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
# ``soothe`` / LangChain beta-API warning from ``TypeSafeClassifier``.
|
|
48
|
+
try:
|
|
49
|
+
from langchain_core._api.beta_decorator import LangChainBetaWarning
|
|
50
|
+
|
|
51
|
+
warnings.filterwarnings("ignore", category=LangChainBetaWarning)
|
|
52
|
+
except Exception: # pragma: no cover - langchain not installed / API changed
|
|
53
|
+
pass
|
|
@@ -298,6 +298,46 @@ def _wire_tool_call_update(
|
|
|
298
298
|
return [ToolStarted(tool=name or "tool", call_id=tc_id, args=args or None)]
|
|
299
299
|
|
|
300
300
|
|
|
301
|
+
def _extract_ask_user_interrupts(
|
|
302
|
+
raw: Any,
|
|
303
|
+
) -> tuple[tuple[dict[str, Any], ...], tuple[str, ...]]:
|
|
304
|
+
"""Pull ``ask_user`` questions and interrupt ids from a ``__interrupt__`` payload.
|
|
305
|
+
|
|
306
|
+
LangGraph emits ``__interrupt__`` as a tuple of ``Interrupt`` objects (or
|
|
307
|
+
dicts). Each carries a ``value`` with the interrupt payload; soothe's
|
|
308
|
+
``ask_user`` tool tags it with ``{"type": "ask_user", "questions": [...]}``.
|
|
309
|
+
|
|
310
|
+
Returns ``(questions, interrupt_ids)`` — only questions from ``ask_user``
|
|
311
|
+
interrupts are surfaced; other interrupt kinds (tool approval, etc.) yield
|
|
312
|
+
an empty questions tuple but still carry their interrupt id so the CLI can
|
|
313
|
+
render a generic "paused for input" message.
|
|
314
|
+
"""
|
|
315
|
+
if not isinstance(raw, (list, tuple)):
|
|
316
|
+
raw = (raw,) if raw is not None else ()
|
|
317
|
+
questions: list[dict[str, Any]] = []
|
|
318
|
+
interrupt_ids: list[str] = []
|
|
319
|
+
for entry in raw:
|
|
320
|
+
value: Any = None
|
|
321
|
+
int_id: str = ""
|
|
322
|
+
# LangGraph Interrupt objects have ``.value`` / ``.id``; serialized
|
|
323
|
+
# dicts use the same keys.
|
|
324
|
+
if hasattr(entry, "value"):
|
|
325
|
+
value = getattr(entry, "value", None)
|
|
326
|
+
int_id = str(getattr(entry, "id", "") or "")
|
|
327
|
+
elif isinstance(entry, dict):
|
|
328
|
+
value = entry.get("value")
|
|
329
|
+
int_id = str(entry.get("id", "") or "")
|
|
330
|
+
if int_id:
|
|
331
|
+
interrupt_ids.append(int_id)
|
|
332
|
+
if isinstance(value, dict) and value.get("type") == "ask_user":
|
|
333
|
+
qs = value.get("questions")
|
|
334
|
+
if isinstance(qs, list):
|
|
335
|
+
for q in qs:
|
|
336
|
+
if isinstance(q, dict):
|
|
337
|
+
questions.append(q)
|
|
338
|
+
return tuple(questions), tuple(interrupt_ids)
|
|
339
|
+
|
|
340
|
+
|
|
301
341
|
async def iter_nano_runtime_events(
|
|
302
342
|
agent: Any,
|
|
303
343
|
*,
|
|
@@ -308,8 +348,14 @@ async def iter_nano_runtime_events(
|
|
|
308
348
|
workspace: str | None = None,
|
|
309
349
|
thread_id: str | None = None,
|
|
310
350
|
interaction_mode: str | None = "agent",
|
|
351
|
+
resume_value: Any = None,
|
|
311
352
|
) -> AsyncIterator[RuntimeEvent]:
|
|
312
|
-
"""Drive ``agent.astream`` and yield sanitized runtime events.
|
|
353
|
+
"""Drive ``agent.astream`` and yield sanitized runtime events.
|
|
354
|
+
|
|
355
|
+
When ``resume_value`` is set, the run resumes a paused graph (an
|
|
356
|
+
``ask_user`` interrupt) with that value via ``Command(resume=...)``
|
|
357
|
+
instead of starting a new turn from ``input_text``.
|
|
358
|
+
"""
|
|
313
359
|
try:
|
|
314
360
|
from langchain_core.messages import AIMessage, HumanMessage, ToolMessage
|
|
315
361
|
except ImportError as exc: # pragma: no cover
|
|
@@ -327,7 +373,15 @@ async def iter_nano_runtime_events(
|
|
|
327
373
|
if workspace:
|
|
328
374
|
configurable["workspace"] = workspace
|
|
329
375
|
|
|
330
|
-
|
|
376
|
+
# Resume a paused graph (ask_user interrupt) rather than starting a new
|
|
377
|
+
# turn. LangGraph's ``Command(resume=...)`` delivers the value to the
|
|
378
|
+
# ``interrupt()`` call that suspended the graph.
|
|
379
|
+
if resume_value is not None:
|
|
380
|
+
from langgraph.types import Command
|
|
381
|
+
|
|
382
|
+
payload: Any = Command(resume=resume_value)
|
|
383
|
+
else:
|
|
384
|
+
payload = {"messages": [HumanMessage(content=input_text)]}
|
|
331
385
|
config = {"configurable": configurable}
|
|
332
386
|
answer = ""
|
|
333
387
|
composing = False
|
|
@@ -340,7 +394,7 @@ async def iter_nano_runtime_events(
|
|
|
340
394
|
|
|
341
395
|
try:
|
|
342
396
|
async for chunk in agent.astream(
|
|
343
|
-
|
|
397
|
+
payload,
|
|
344
398
|
config=config,
|
|
345
399
|
stream_mode=["messages", "updates", "custom"],
|
|
346
400
|
subgraphs=True,
|
|
@@ -369,7 +423,12 @@ async def iter_nano_runtime_events(
|
|
|
369
423
|
|
|
370
424
|
if mode == "updates" and isinstance(data, dict):
|
|
371
425
|
if "__interrupt__" in data:
|
|
372
|
-
|
|
426
|
+
questions, interrupt_ids = _extract_ask_user_interrupts(data["__interrupt__"])
|
|
427
|
+
yield InterruptWaiting(
|
|
428
|
+
message="Waiting for input…",
|
|
429
|
+
questions=questions,
|
|
430
|
+
interrupt_ids=interrupt_ids,
|
|
431
|
+
)
|
|
373
432
|
continue
|
|
374
433
|
# Plan steps (todos) and host middleware phases are the only
|
|
375
434
|
# signal soothe gives us about *what* it is doing between tool
|
|
@@ -63,7 +63,16 @@ class OutputTextDelta:
|
|
|
63
63
|
|
|
64
64
|
@dataclass(frozen=True, slots=True)
|
|
65
65
|
class InterruptWaiting:
|
|
66
|
+
"""Agent paused for human input (``ask_user`` interrupt).
|
|
67
|
+
|
|
68
|
+
When the pause comes from soothe's ``ask_user`` tool, ``questions`` carries
|
|
69
|
+
the structured question specs the model asked, so the CLI can render them
|
|
70
|
+
and accept an answer that resumes the run on a follow-up invocation.
|
|
71
|
+
"""
|
|
72
|
+
|
|
66
73
|
message: str | None = None
|
|
74
|
+
questions: tuple[dict[str, Any], ...] = ()
|
|
75
|
+
interrupt_ids: tuple[str, ...] = ()
|
|
67
76
|
|
|
68
77
|
|
|
69
78
|
@dataclass(frozen=True, slots=True)
|
|
@@ -92,6 +101,10 @@ class RunRequest:
|
|
|
92
101
|
session: str | None = None
|
|
93
102
|
metadata: dict[str, Any] | None = None
|
|
94
103
|
run_id: str | None = None
|
|
104
|
+
# When set, the run resumes a paused graph (``ask_user`` interrupt) with the
|
|
105
|
+
# given value instead of starting a new turn from ``input_text``. The value
|
|
106
|
+
# is passed to LangGraph's ``Command(resume=...)``.
|
|
107
|
+
resume_value: Any = None
|
|
95
108
|
|
|
96
109
|
|
|
97
110
|
@dataclass(frozen=True, slots=True)
|
|
@@ -35,6 +35,12 @@ def _create_dual_stack_socket(host: str, port: int) -> socket.socket:
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def main() -> None:
|
|
38
|
+
# Silence noisy third-party warnings (requests version-mismatch,
|
|
39
|
+
# LangChain beta-API) before the agent stack is imported.
|
|
40
|
+
from flowjet.core._warnings import suppress_known_warnings
|
|
41
|
+
|
|
42
|
+
suppress_known_warnings()
|
|
43
|
+
|
|
38
44
|
# Pull in a ~/.soothe/config copy before the first agent build. Kept out of
|
|
39
45
|
# create_app(): the ASGI app is built at import time, and importing a module
|
|
40
46
|
# must not write files.
|
|
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
|
{flowjet-2.0.7 → flowjet-2.0.9}/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
|
|
File without changes
|
{flowjet-2.0.7 → flowjet-2.0.9}/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.0.7 → flowjet-2.0.9}/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.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/patterns/loop.json
RENAMED
|
File without changes
|
|
File without changes
|
{flowjet-2.0.7 → flowjet-2.0.9}/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.0.7 → flowjet-2.0.9}/src/flowjet/builtin_skills/research-bootstrap/references/backends.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{flowjet-2.0.7 → flowjet-2.0.9}/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
|