create-windy 0.3.2 → 0.3.5
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.
- package/README.md +27 -9
- package/dist/cli.js +825 -117
- package/package.json +1 -1
- package/template/.agents/skills/windy-business-module/SKILL.md +16 -3
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +4 -0
- package/template/README.md +18 -11
- package/template/_gitignore +1 -0
- package/template/apps/agent-server/README.md +2 -0
- package/template/apps/agent-server/pyproject.toml +8 -0
- package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +87 -10
- package/template/apps/agent-server/src/southwind_agent_server/adk_model.py +18 -3
- package/template/apps/agent-server/src/southwind_agent_server/adk_tools.py +78 -11
- package/template/apps/agent-server/src/southwind_agent_server/app.py +120 -115
- package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +153 -0
- package/template/apps/agent-server/src/southwind_agent_server/config.py +29 -0
- package/template/apps/agent-server/src/southwind_agent_server/contracts.py +81 -1
- package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +8 -0
- package/template/apps/agent-server/src/southwind_agent_server/engine.py +28 -0
- package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +41 -0
- package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +62 -0
- package/template/apps/agent-server/src/southwind_agent_server/lease.py +15 -0
- package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +76 -0
- package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +112 -20
- package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +14 -1
- package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +329 -0
- package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +332 -0
- package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +64 -3
- package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +68 -0
- package/template/apps/agent-server/src/southwind_agent_server/service.py +218 -56
- package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +36 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +107 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +65 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +16 -0
- package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +89 -57
- package/template/apps/agent-server/src/southwind_agent_server/store.py +105 -2
- package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +40 -0
- package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +89 -0
- package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +72 -0
- package/template/apps/agent-server/tests/test_adk_adapter.py +6 -2
- package/template/apps/agent-server/tests/test_api.py +24 -1
- package/template/apps/agent-server/tests/test_artifact_input.py +110 -0
- package/template/apps/agent-server/tests/test_config.py +4 -0
- package/template/apps/agent-server/tests/test_fingerprint.py +10 -0
- package/template/apps/agent-server/tests/test_multimodal.py +51 -0
- package/template/apps/agent-server/tests/test_openai_provider.py +6 -2
- package/template/apps/agent-server/tests/test_postgres_store.py +131 -0
- package/template/apps/agent-server/tests/test_provider_governance.py +61 -0
- package/template/apps/agent-server/tests/test_sqlite_store.py +95 -10
- package/template/apps/agent-server/tests/test_telemetry.py +25 -0
- package/template/apps/agent-server/tests/test_tool_approval.py +28 -0
- package/template/apps/agent-server/uv.lock +165 -0
- package/template/apps/document-server/Dockerfile +19 -0
- package/template/apps/document-server/pyproject.toml +43 -0
- package/template/apps/document-server/src/southwind_document_server/__init__.py +1 -0
- package/template/apps/document-server/src/southwind_document_server/adapter.py +337 -0
- package/template/apps/document-server/src/southwind_document_server/app.py +151 -0
- package/template/apps/document-server/src/southwind_document_server/config.py +94 -0
- package/template/apps/document-server/src/southwind_document_server/contracts.py +103 -0
- package/template/apps/document-server/src/southwind_document_server/service.py +149 -0
- package/template/apps/document-server/src/southwind_document_server/store.py +185 -0
- package/template/apps/document-server/tests/__init__.py +1 -0
- package/template/apps/document-server/tests/test_config.py +42 -0
- package/template/apps/document-server/tests/test_service.py +140 -0
- package/template/apps/document-server/uv.lock +430 -0
- package/template/apps/embedding-server/Dockerfile +17 -0
- package/template/apps/embedding-server/pyproject.toml +44 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/__init__.py +1 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/adapter.py +254 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/app.py +119 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/config.py +120 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/contracts.py +106 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/error.py +6 -0
- package/template/apps/embedding-server/src/southwind_embedding_server/image_input.py +87 -0
- package/template/apps/embedding-server/tests/__init__.py +1 -0
- package/template/apps/embedding-server/tests/test_adapter.py +92 -0
- package/template/apps/embedding-server/tests/test_config.py +38 -0
- package/template/apps/embedding-server/uv.lock +449 -0
- package/template/apps/server/src/agent/background-operation-port.ts +37 -0
- package/template/apps/server/src/agent/background-operation.test.ts +231 -0
- package/template/apps/server/src/agent/background-operation.ts +252 -0
- package/template/apps/server/src/agent/drizzle-run-binding-repository.ts +114 -0
- package/template/apps/server/src/agent/execution-grants.ts +7 -1
- package/template/apps/server/src/agent/fake-runtime.test-support.ts +43 -0
- package/template/apps/server/src/agent/idempotency-key.test.ts +28 -0
- package/template/apps/server/src/agent/idempotency-key.ts +11 -0
- package/template/apps/server/src/agent/remote-runtime.test.ts +115 -1
- package/template/apps/server/src/agent/remote-runtime.ts +173 -5
- package/template/apps/server/src/agent/run-authorization.test-support.ts +9 -0
- package/template/apps/server/src/agent/run-authorization.test.ts +126 -0
- package/template/apps/server/src/agent/run-authorization.ts +180 -0
- package/template/apps/server/src/agent/run-binding-repository.ts +93 -0
- package/template/apps/server/src/agent/run-contracts.ts +88 -1
- package/template/apps/server/src/agent/run-definition-support.ts +58 -0
- package/template/apps/server/src/agent/run-errors.ts +25 -0
- package/template/apps/server/src/agent/run-facade.test.ts +57 -46
- package/template/apps/server/src/agent/run-facade.ts +185 -65
- package/template/apps/server/src/agent/run-release.ts +78 -0
- package/template/apps/server/src/agent/run-route-input.ts +169 -0
- package/template/apps/server/src/agent/run-routes.ts +63 -76
- package/template/apps/server/src/agent/runtime-bootstrap.ts +169 -13
- package/template/apps/server/src/agent/sandbox-client.ts +200 -0
- package/template/apps/server/src/agent/sandbox-protocol.ts +76 -0
- package/template/apps/server/src/agent/sandbox-registry.ts +205 -0
- package/template/apps/server/src/agent/sandbox-runtime.test.ts +137 -0
- package/template/apps/server/src/agent/sandbox-worker-server.ts +195 -0
- package/template/apps/server/src/agent/sandbox-worker.ts +12 -0
- package/template/apps/server/src/agent/tool-approval.test.ts +75 -0
- package/template/apps/server/src/agent/tool-approval.ts +115 -0
- package/template/apps/server/src/agent/tool-audit.ts +62 -0
- package/template/apps/server/src/agent/tool-host.test.ts +39 -11
- package/template/apps/server/src/agent/tool-host.ts +184 -17
- package/template/apps/server/src/agent/tool-registry.ts +52 -47
- package/template/apps/server/src/agent/vision-facade.test.ts +256 -0
- package/template/apps/server/src/agent/vision-input.ts +120 -0
- package/template/apps/server/src/ai-artifact/codec.test.ts +44 -0
- package/template/apps/server/src/ai-artifact/codec.ts +137 -0
- package/template/apps/server/src/ai-artifact/routes.ts +37 -0
- package/template/apps/server/src/ai-artifact/runtime.ts +205 -0
- package/template/apps/server/src/application-services.ts +62 -2
- package/template/apps/server/src/auth/reauthentication.test.ts +40 -0
- package/template/apps/server/src/auth/reauthentication.ts +19 -0
- package/template/apps/server/src/auth/runtime.ts +9 -1
- package/template/apps/server/src/data-access/context.ts +6 -4
- package/template/apps/server/src/data-access/scope-snapshot.ts +27 -0
- package/template/apps/server/src/data-governance/export/approval-port.ts +6 -3
- package/template/apps/server/src/data-governance/export/authorization-port.test.ts +23 -4
- package/template/apps/server/src/data-governance/export/authorization-port.ts +89 -25
- package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +2 -0
- package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -0
- package/template/apps/server/src/data-governance/export/job-runtime.test.ts +15 -4
- package/template/apps/server/src/data-governance/export/job-runtime.ts +68 -15
- package/template/apps/server/src/data-governance/export/ndjson-stream.ts +25 -6
- package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +4 -2
- package/template/apps/server/src/data-governance/export/renderer-job-runtime.test.ts +235 -0
- package/template/apps/server/src/data-governance/export/renderer-runtime.ts +293 -0
- package/template/apps/server/src/data-governance/export/renderer-selection.test.ts +67 -0
- package/template/apps/server/src/data-governance/export/repository.test.ts +2 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +13 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.ts +2 -0
- package/template/apps/server/src/data-governance/export/routes.ts +11 -1
- package/template/apps/server/src/data-governance/export/scope-snapshot.ts +6 -18
- package/template/apps/server/src/data-governance/export/service-support.ts +188 -0
- package/template/apps/server/src/data-governance/export/service.ts +90 -113
- package/template/apps/server/src/data-governance/export/source.ts +101 -0
- package/template/apps/server/src/data-governance/export/types.ts +27 -0
- package/template/apps/server/src/document/contracts.ts +76 -0
- package/template/apps/server/src/document/facade.ts +339 -0
- package/template/apps/server/src/document/remote-runtime.test.ts +96 -0
- package/template/apps/server/src/document/remote-runtime.ts +223 -0
- package/template/apps/server/src/document/routes.ts +193 -0
- package/template/apps/server/src/embedding/contracts.ts +83 -0
- package/template/apps/server/src/embedding/error.ts +10 -0
- package/template/apps/server/src/embedding/facade.ts +217 -0
- package/template/apps/server/src/embedding/input.ts +172 -0
- package/template/apps/server/src/embedding/remote-runtime.test.ts +66 -0
- package/template/apps/server/src/embedding/remote-runtime.ts +218 -0
- package/template/apps/server/src/embedding/routes.ts +152 -0
- package/template/apps/server/src/index.ts +40 -43
- package/template/apps/server/src/jobs/artifact-service.test.ts +14 -2
- package/template/apps/server/src/jobs/artifact-service.ts +10 -0
- package/template/apps/server/src/jobs/drizzle-execution-repository.ts +17 -18
- package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +19 -1
- package/template/apps/server/src/jobs/drizzle-mappers.ts +4 -1
- package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +49 -2
- package/template/apps/server/src/jobs/drizzle-repository.ts +1 -0
- package/template/apps/server/src/jobs/execution-repository.ts +17 -0
- package/template/apps/server/src/jobs/execution.test.ts +34 -0
- package/template/apps/server/src/jobs/in-memory-control.ts +135 -0
- package/template/apps/server/src/jobs/in-memory-execution.ts +34 -65
- package/template/apps/server/src/jobs/legacy-service-runtime.ts +5 -2
- package/template/apps/server/src/jobs/repository.ts +3 -0
- package/template/apps/server/src/jobs/worker.ts +80 -41
- package/template/apps/server/src/module-host/ai-operation-port.ts +170 -0
- package/template/apps/server/src/module-host/durable-context.test.ts +312 -0
- package/template/apps/server/src/module-host/durable-context.ts +124 -0
- package/template/apps/server/src/module-host/durable-handler-registration.ts +72 -0
- package/template/apps/server/src/module-host/governed-export-route-support.ts +171 -0
- package/template/apps/server/src/module-host/governed-export-routes.test.ts +327 -0
- package/template/apps/server/src/module-host/governed-export-routes.ts +238 -0
- package/template/apps/server/src/module-host/governed-renderer-registration.test.ts +247 -0
- package/template/apps/server/src/module-host/governed-resource-routes.ts +331 -0
- package/template/apps/server/src/module-host/governed-resources.test.ts +344 -0
- package/template/apps/server/src/module-host/governed-resources.ts +203 -0
- package/template/apps/server/src/module-host/http-runtime.ts +95 -0
- package/template/apps/server/src/module-host/initialize-contracts.ts +14 -0
- package/template/apps/server/src/module-host/initialize.test.ts +49 -1
- package/template/apps/server/src/module-host/initialize.ts +39 -16
- package/template/apps/server/src/module-host/job-port.test.ts +262 -0
- package/template/apps/server/src/module-host/job-port.ts +334 -0
- package/template/apps/server/src/module-host/request-context.test.ts +88 -2
- package/template/apps/server/src/module-host/request-context.ts +56 -22
- package/template/apps/server/src/module-host/route-installer.test.ts +10 -0
- package/template/apps/server/src/module-host/route-installer.ts +36 -1
- package/template/apps/server/src/module-host/sandbox-tool-registration.ts +42 -0
- package/template/apps/server/src/module-host/tool-handlers.ts +67 -31
- package/template/apps/server/src/module-host.ts +1 -0
- package/template/apps/server/src/module-runtime-validation.ts +7 -3
- package/template/apps/server/src/speech/contracts.ts +76 -0
- package/template/apps/server/src/speech/facade.ts +316 -0
- package/template/apps/server/src/speech/remote-runtime.test.ts +88 -0
- package/template/apps/server/src/speech/remote-runtime.ts +227 -0
- package/template/apps/server/src/speech/routes.ts +180 -0
- package/template/apps/server/src/system/actor.ts +39 -0
- package/template/apps/server/src/system/route-helpers.ts +1 -0
- package/template/apps/server/src/workflow/service.ts +2 -1
- package/template/apps/speech-server/Dockerfile +22 -0
- package/template/apps/speech-server/pyproject.toml +43 -0
- package/template/apps/speech-server/src/southwind_speech_server/__init__.py +1 -0
- package/template/apps/speech-server/src/southwind_speech_server/adapter.py +249 -0
- package/template/apps/speech-server/src/southwind_speech_server/app.py +183 -0
- package/template/apps/speech-server/src/southwind_speech_server/config.py +100 -0
- package/template/apps/speech-server/src/southwind_speech_server/contracts.py +103 -0
- package/template/apps/speech-server/src/southwind_speech_server/errors.py +6 -0
- package/template/apps/speech-server/src/southwind_speech_server/normalizer.py +108 -0
- package/template/apps/speech-server/src/southwind_speech_server/output_validation.py +128 -0
- package/template/apps/speech-server/src/southwind_speech_server/service.py +162 -0
- package/template/apps/speech-server/src/southwind_speech_server/store.py +209 -0
- package/template/apps/speech-server/tests/__init__.py +1 -0
- package/template/apps/speech-server/tests/test_config.py +33 -0
- package/template/apps/speech-server/tests/test_service.py +154 -0
- package/template/apps/speech-server/uv.lock +430 -0
- package/template/apps/web/src/app/business-routes.ts +22 -0
- package/template/apps/web/src/components/common/AccessSnapshotBoundary.vue +112 -0
- package/template/apps/web/src/components/common/AccessSnapshotBoundary.webtest.ts +130 -0
- package/template/apps/web/src/components/common/AccessSnapshotNotice.vue +117 -0
- package/template/apps/web/src/components/common/FormDialog.vue +6 -0
- package/template/apps/web/src/components/common/ModalLayout.webtest.ts +13 -0
- package/template/apps/web/src/composables/access-snapshot-change.ts +131 -0
- package/template/apps/web/src/composables/access-snapshot-change.webtest.ts +103 -0
- package/template/apps/web/src/composables/useAccessSnapshot.ts +48 -2
- package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +54 -0
- package/template/apps/web/src/composables/useAccessSnapshotMonitor.ts +42 -0
- package/template/apps/web/src/layout/AppShell.vue +28 -25
- package/template/apps/web/src/layout/AppShell.webtest.ts +1 -0
- package/template/apps/web/src/router/business-routes.ts +68 -0
- package/template/apps/web/src/router/business-routes.webtest.ts +85 -0
- package/template/apps/web/src/router/index.ts +7 -0
- package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
- package/template/apps/web/src/services/access-api.ts +5 -1
- package/template/apps/web/src/services/access-api.webtest.ts +35 -0
- package/template/docker-compose.yml +127 -0
- package/template/docs/architecture/ai-egress.md +12 -9
- package/template/docs/architecture/ai-runtime.md +23 -11
- package/template/docs/architecture/durable-jobs.md +25 -3
- package/template/docs/architecture/foundation-infrastructure.md +163 -0
- package/template/docs/architecture/module-host.md +115 -0
- package/template/docs/architecture/server-module-interface.md +39 -0
- package/template/docs/architecture/web-access-snapshot-resilience.md +60 -0
- package/template/docs/development/business-web-routes.md +66 -0
- package/template/docs/development/custom-login-page.md +3 -3
- package/template/docs/development/module-lifecycle.md +71 -0
- package/template/docs/operations/observability.md +5 -1
- package/template/docs/platform/agent-runtime.md +21 -11
- package/template/docs/platform/agent-tool-sandbox.md +58 -0
- package/template/docs/platform/agent-tools.md +5 -0
- package/template/docs/platform/document-ai-runtime.md +204 -0
- package/template/docs/platform/governed-export-renderers.md +132 -0
- package/template/docs/platform/navigation-registry.md +5 -0
- package/template/docs/platform/organization-membership.md +2 -1
- package/template/docs/platform/speech-ai-runtime.md +156 -0
- package/template/docs/platform/system-crud-api.md +7 -1
- package/template/docs/platform/vision-ai-runtime.md +97 -0
- package/template/docs/platform/web-system-crud.md +6 -0
- package/template/package.json +16 -2
- package/template/packages/ai-client/index.ts +4 -0
- package/template/packages/ai-client/package.json +5 -2
- package/template/packages/ai-client/src/agent/client/artifact.ts +26 -0
- package/template/packages/ai-client/src/agent/client/attach.test.ts +124 -0
- package/template/packages/ai-client/src/agent/client/client.ts +119 -7
- package/template/packages/ai-client/src/agent/client/run.ts +14 -0
- package/template/packages/ai-client/src/agent/client/types.ts +18 -0
- package/template/packages/ai-client/src/agent/client/vision.test.ts +53 -0
- package/template/packages/ai-client/src/agent/contracts/contracts.test.ts +1 -0
- package/template/packages/ai-client/src/agent/contracts/events.ts +33 -0
- package/template/packages/ai-client/src/agent/contracts/runs.ts +71 -0
- package/template/packages/ai-client/src/agent/index.ts +1 -0
- package/template/packages/ai-client/src/artifact-ref.ts +8 -0
- package/template/packages/ai-client/src/document/client.test.ts +114 -0
- package/template/packages/ai-client/src/document/client.ts +134 -0
- package/template/packages/ai-client/src/document/contracts.ts +152 -0
- package/template/packages/ai-client/src/document/error.ts +43 -0
- package/template/packages/ai-client/src/document/index.ts +3 -0
- package/template/packages/ai-client/src/document/run.ts +104 -0
- package/template/packages/ai-client/src/document/validation.ts +115 -0
- package/template/packages/ai-client/src/embedding/client.test.ts +77 -0
- package/template/packages/ai-client/src/embedding/client.ts +96 -0
- package/template/packages/ai-client/src/embedding/contracts.ts +46 -0
- package/template/packages/ai-client/src/embedding/error.ts +61 -0
- package/template/packages/ai-client/src/embedding/index.ts +3 -0
- package/template/packages/ai-client/src/embedding/validation.ts +117 -0
- package/template/packages/ai-client/src/speech/client.test.ts +135 -0
- package/template/packages/ai-client/src/speech/client.ts +104 -0
- package/template/packages/ai-client/src/speech/contracts.ts +129 -0
- package/template/packages/ai-client/src/speech/error.ts +43 -0
- package/template/packages/ai-client/src/speech/index.ts +3 -0
- package/template/packages/ai-client/src/speech/run.ts +133 -0
- package/template/packages/ai-client/src/speech/validation.ts +132 -0
- package/template/packages/config/package.json +2 -2
- package/template/packages/database/drizzle/0039_early_ezekiel_stane.sql +1 -0
- package/template/packages/database/drizzle/0040_colossal_baron_strucker.sql +63 -0
- package/template/packages/database/drizzle/0041_yummy_prowler.sql +21 -0
- package/template/packages/database/drizzle/0042_puzzling_rumiko_fujikawa.sql +27 -0
- package/template/packages/database/drizzle/meta/0039_snapshot.json +7755 -0
- package/template/packages/database/drizzle/meta/0040_snapshot.json +8150 -0
- package/template/packages/database/drizzle/meta/0041_snapshot.json +8323 -0
- package/template/packages/database/drizzle/meta/0042_snapshot.json +8541 -0
- package/template/packages/database/drizzle/meta/_journal.json +28 -0
- package/template/packages/database/package.json +2 -2
- package/template/packages/database/src/agent-runtime-schema.test.ts +54 -0
- package/template/packages/database/src/schema/agent-runtime.ts +149 -0
- package/template/packages/database/src/schema/common.ts +2 -14
- package/template/packages/database/src/schema/durable-jobs.ts +5 -0
- package/template/packages/database/src/schema/governed-exports.ts +17 -5
- package/template/packages/database/src/schema/index.ts +3 -0
- package/template/packages/database/src/schema-durable-recovery.test.ts +31 -0
- package/template/packages/database/src/schema-governed-exports.test.ts +21 -1
- package/template/packages/database/src/schema.test.ts +6 -23
- package/template/packages/jobs/package.json +3 -2
- package/template/packages/jobs/src/handlers.test.ts +13 -0
- package/template/packages/jobs/src/handlers.ts +7 -1
- package/template/packages/jobs/src/types.ts +4 -0
- package/template/packages/modules/package.json +2 -2
- package/template/packages/modules/src/ai-operation-composition.test-support.ts +165 -0
- package/template/packages/modules/src/ai-operation-composition.test.ts +91 -127
- package/template/packages/modules/src/ai-operation-composition.ts +59 -1
- package/template/packages/modules/src/manifest.ts +25 -1
- package/template/packages/modules/src/tool-composition.ts +18 -0
- package/template/packages/server-sdk/index.ts +50 -0
- package/template/packages/server-sdk/package.json +10 -4
- package/template/packages/server-sdk/src/ai-artifact-port.ts +34 -0
- package/template/packages/server-sdk/src/ai-operation-port.ts +65 -0
- package/template/packages/server-sdk/src/ai-operation-registration.ts +42 -1
- package/template/packages/server-sdk/src/background-ai-port.ts +43 -0
- package/template/packages/server-sdk/src/data-governance-registration.ts +116 -0
- package/template/packages/server-sdk/src/durable-handler.ts +29 -0
- package/template/packages/server-sdk/src/jobs-port.ts +69 -0
- package/template/packages/server-sdk/src/module-host.ts +16 -2
- package/template/packages/server-sdk/src/request-context.ts +6 -2
- package/template/packages/server-sdk/src/sandbox-tool.ts +21 -0
- package/template/packages/server-sdk/src/tool-registration.ts +2 -0
- package/template/packages/shared/package.json +1 -1
- package/template/packages/shared/src/rbac.ts +30 -0
package/package.json
CHANGED
|
@@ -28,14 +28,26 @@ description: "Windy 业务模块、Manifest、Repository、Service、Agent Tool
|
|
|
28
28
|
project-owned Repository 回查资源与 fileId 绑定及对象级授权,只返回布尔判定,
|
|
29
29
|
再通过 `context.storage.openResourceFile()` 取得最小元数据与流。禁止注入
|
|
30
30
|
UploadRepository、BlobStore 或申请平台 manage Repository。
|
|
31
|
-
6.
|
|
31
|
+
6. 业务资源包含敏感字段时,在 Manifest 一次声明 Data Policy、standard read、
|
|
32
|
+
sensitive-disclosure reveal、governed-export Permission 与 masked/reveal API 绑定,
|
|
33
|
+
再用 `registerGovernedResources()` 分别注册对象授权 Resolver 和去除治理字段的投影。
|
|
34
|
+
需要导出时再登记四个 Manifest API 绑定、受控查询校验和 cursor 分页 Source;审批、
|
|
35
|
+
Durable Job、水印、TTL、下载与取消由宿主负责。业务不自行签发明文 Grant、校验密码,
|
|
36
|
+
也不接触 Workflow、BlobStore 或平台 Repository。
|
|
37
|
+
7. 若项目包含 `system.agent`,`operation=query` 的 Tool 会由同一 Registry 自动进入
|
|
32
38
|
MCP;不要编辑 MCP Adapter 或复制 Tool 定义。写操作在幂等、审批和结果追踪闭环前
|
|
33
39
|
不通过 MCP 暴露。
|
|
34
|
-
|
|
40
|
+
对无需 Actor、Repository、Secret、文件系统或外网的纯计算 Tool,可改用
|
|
41
|
+
`setupSandbox()` 注册;此入口必须同步且无副作用,Handler 只能使用输入、
|
|
42
|
+
`idempotencyKey` 与 `AbortSignal`。需要业务数据或外部服务的 Tool 必须保留在普通
|
|
43
|
+
`setup()`,不能为了使用 Sandbox 绕过依赖边界。
|
|
44
|
+
8. 补 Manifest/Composition、Repository/Service、Guard 拒绝和 Handler 契约测试。
|
|
35
45
|
涉及 Tool 时还要覆盖 Schema 拒绝、数据范围与未授权发现/调用;涉及可选模块时覆盖
|
|
36
46
|
Starter 的文件、依赖和数据库裁剪。涉及资源文件时还要覆盖跨上传者成功、资源绑定/
|
|
37
47
|
purpose/Feature/Permission/Scope 任一拒绝、最小元数据与成功/拒绝审计。
|
|
38
|
-
|
|
48
|
+
涉及 Sandbox Tool 时还要覆盖无网络、无平台 Secret、无宿主数据挂载、Worker
|
|
49
|
+
重启恢复,以及策略拒绝与业务失败审计分类。
|
|
50
|
+
9. 更新长期文档,运行受影响测试、`bun run typecheck` 和 `bun run lint`,按一个完整
|
|
39
51
|
小切片提交。
|
|
40
52
|
|
|
41
53
|
## 代码事实源
|
|
@@ -44,6 +56,7 @@ description: "Windy 业务模块、Manifest、Repository、Service、Agent Tool
|
|
|
44
56
|
- Tool 组合校验:`packages/modules/src/tool-composition.ts`
|
|
45
57
|
- 模块 Host 契约:`packages/server-sdk/src/module-host.ts`
|
|
46
58
|
- Tool Handler 契约:`packages/server-sdk/src/tool-registration.ts`
|
|
59
|
+
- Sandbox Tool 契约:`packages/server-sdk/src/sandbox-tool.ts`
|
|
47
60
|
- 可移除业务示例:`packages/example-work-order/`、`apps/server/src/work-order/`
|
|
48
61
|
- 业务模块安装入口:`apps/server/src/installed-business-modules.ts`
|
|
49
62
|
- MCP 与统一执行边界:`docs/architecture/mcp-business-capabilities.md`
|
package/template/AGENTS.md
CHANGED
|
@@ -47,6 +47,10 @@
|
|
|
47
47
|
- 定制 404、500、维护中或网络异常页时,只修改 project-owned 的
|
|
48
48
|
`apps/web/src/app/error-pages.ts`,并把业务 SFC 放在 `apps/web/src/app/`;
|
|
49
49
|
保留四个类型化注册项,不要为换视觉修改 Router、HTTP 核心或平台默认错误页。
|
|
50
|
+
- 新增业务管理页面时,在业务 Module Manifest 注册 Feature、Permission、菜单和
|
|
51
|
+
Admin Route,再把 Vue 页面绑定到 project-owned 的
|
|
52
|
+
`apps/web/src/app/business-routes.ts`;不要修改 Router 或 AppSidebar。导航来自
|
|
53
|
+
服务端 Manifest 快照,接入见 `docs/development/business-web-routes.md`。
|
|
50
54
|
- 业务 Agent Operation 开启 Provider 出网时,必须在 Manifest 同时声明最小
|
|
51
55
|
`providerDataPolicy.inputFields` JSON Pointer allowlist 与
|
|
52
56
|
`envelopeFields`;raw input 会在进入 `prepare` 前裁剪并执行 DLP。接入与升级
|
package/template/README.md
CHANGED
|
@@ -60,9 +60,9 @@ Skill 完成该能力”。Skill 只指导开发流程;Feature、Permission、
|
|
|
60
60
|
运行时事实仍以 Module Manifest 与平台 Registry 为准。
|
|
61
61
|
|
|
62
62
|
当前组合未包含 `system.agent`,MCP Server、Agent Tool Host 和相关文档已被
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
物理裁剪。创建时可增加 `--module system.agent` 或使用 `--all-modules`;已部署
|
|
64
|
+
项目使用 `bun run windy module add system.agent`,不要手工复制 MCP Adapter 或
|
|
65
|
+
另建授权链。仓库 Skill 仍可用于普通业务模块开发。
|
|
66
66
|
|
|
67
67
|
|
|
68
68
|
|
|
@@ -99,8 +99,8 @@ create-windy 在本机 `.env` 中随机生成的 `WINDY_BOOTSTRAP_ADMIN_PASSWORD
|
|
|
99
99
|
| 法律许可 | `UNLICENSED` |
|
|
100
100
|
|
|
101
101
|
平台当前注册的全部模块如下。H0 表示 profile 锁定核心;H2 表示创建时可以物理包含或
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
排除;H3 还具备部署期安装、更新、数据保留卸载和重装证据。通用生命周期命令会保守
|
|
103
|
+
处理所有目录模块,但只有通过完整 H3 回归的模块才标记为 H3。
|
|
104
104
|
|
|
105
105
|
| Module Key | 当前项目 | 热插拔可靠度 | 说明 |
|
|
106
106
|
| ---------- | -------- | ------------ | ---- |
|
|
@@ -119,14 +119,17 @@ create-windy 在本机 `.env` 中随机生成的 `WINDY_BOOTSTRAP_ADMIN_PASSWORD
|
|
|
119
119
|
| `system.bulk-data` | 未包含 | H2 | 批量导入导出与结果留存。 |
|
|
120
120
|
| `system.search` | 未包含 | H2 | 权限感知搜索与 Provider 聚合。 |
|
|
121
121
|
| `system.data-governance` | 未包含 | H2 | 敏感字段、明文访问和治理导出。 |
|
|
122
|
-
| `work-order` | 未包含 |
|
|
122
|
+
| `work-order` | 未包含 | H3 | 可替换的业务模块接入示例。 |
|
|
123
123
|
|
|
124
124
|
项目自有业务模块以 `apps/server/src/installed-business-modules.ts` 装配的 Module Manifest
|
|
125
|
-
|
|
125
|
+
为准;对应 Vue 页面在 project-owned 的
|
|
126
|
+
`apps/web/src/app/business-routes.ts` 注册,侧栏继续从服务端 Manifest 快照生成。
|
|
127
|
+
不要为增加业务页面修改 shared-scaffold Router 或 AppSidebar。shared-scaffold README
|
|
128
|
+
不复制项目业务 Key,避免平台升级固化产品命名。
|
|
126
129
|
|
|
127
130
|
精确生成来源和选择记录在 `.windy/generation.json`。当前版本已提供可回滚的
|
|
128
|
-
`windy update
|
|
129
|
-
|
|
131
|
+
`windy update` 与 `windy module list/add/update/remove`。Feature Flag 关闭仍不
|
|
132
|
+
等于模块卸载。
|
|
130
133
|
|
|
131
134
|
## 常用命令
|
|
132
135
|
|
|
@@ -142,6 +145,9 @@ bun run build
|
|
|
142
145
|
bun run windy doctor
|
|
143
146
|
bun run windy update --check
|
|
144
147
|
bun run windy update --dry-run
|
|
148
|
+
bun run windy module list
|
|
149
|
+
bun run windy module add work-order --dry-run
|
|
150
|
+
bun run windy module remove work-order --dry-run
|
|
145
151
|
bun run windy reconcile --to <精确目标版本>
|
|
146
152
|
bun run lint
|
|
147
153
|
bun run format
|
|
@@ -178,8 +184,9 @@ create-windy 默认建立 `main` 分支并创建 `chore: initialize project` 首
|
|
|
178
184
|
没有配置 Git 用户身份,文件会保留在暂存区;配置身份后手动提交即可。
|
|
179
185
|
|
|
180
186
|
当前已交付的 Windy 更新器会根据 Project Lock 和文件所有权,从 npm 历史 artifact
|
|
181
|
-
重建 Base
|
|
182
|
-
|
|
187
|
+
重建 Base 并执行三方合并;它不连接私有源仓库,也不会静默覆盖项目代码。模块
|
|
188
|
+
生命周期命令复用同一计划、事务、验证与恢复边界;卸载默认保留数据库数据,并要求
|
|
189
|
+
显式确认数据处置计划。
|
|
183
190
|
|
|
184
191
|
## License
|
|
185
192
|
|
package/template/_gitignore
CHANGED
|
@@ -32,6 +32,8 @@ export QWEN_API_URL='https://dashscope-intl.aliyuncs.com/compatible-mode/v1'
|
|
|
32
32
|
export QWEN_API_KEY='<server-secret>'
|
|
33
33
|
export QWEN_MODEL='qwen-plus'
|
|
34
34
|
export AI_PROVIDER_HTTPS_HOST_ALLOWLIST='dashscope-intl.aliyuncs.com'
|
|
35
|
+
export AI_PROVIDER_CAPABILITIES='text-generation'
|
|
36
|
+
export AI_PROVIDER_INPUT_MODALITIES='text'
|
|
35
37
|
export AGENT_RUN_STORE_PATH='.data/agent-runs.sqlite3'
|
|
36
38
|
export AI_PROVIDER_AUDIT_STORE_PATH='.data/provider-audit.sqlite3'
|
|
37
39
|
export AI_PROVIDER_AUDIT_RETENTION_DAYS='90'
|
|
@@ -4,9 +4,16 @@ version = "0.1.0"
|
|
|
4
4
|
description = "Southwind AI canonical Agent Runtime server"
|
|
5
5
|
requires-python = ">=3.12,<3.13"
|
|
6
6
|
dependencies = [
|
|
7
|
+
"cryptography==49.0.0",
|
|
7
8
|
"fastapi==0.139.2",
|
|
8
9
|
"google-adk==2.5.0",
|
|
9
10
|
"httpx==0.28.1",
|
|
11
|
+
"jsonschema==4.26.0",
|
|
12
|
+
"opentelemetry-api==1.42.1",
|
|
13
|
+
"opentelemetry-exporter-otlp-proto-http==1.42.1",
|
|
14
|
+
"opentelemetry-sdk==1.42.1",
|
|
15
|
+
"pillow==12.3.0",
|
|
16
|
+
"psycopg[binary,pool]==3.3.4",
|
|
10
17
|
"pydantic==2.13.4",
|
|
11
18
|
"uvicorn==0.51.0",
|
|
12
19
|
]
|
|
@@ -17,6 +24,7 @@ dev = [
|
|
|
17
24
|
"pytest==9.1.1",
|
|
18
25
|
"pytest-asyncio==1.4.0",
|
|
19
26
|
"ruff==0.15.22",
|
|
27
|
+
"types-jsonschema==4.26.0.20260518",
|
|
20
28
|
]
|
|
21
29
|
|
|
22
30
|
[tool.pytest.ini_options]
|
|
@@ -12,7 +12,7 @@ from google.genai import types
|
|
|
12
12
|
|
|
13
13
|
from .adk_failure import AdkFailureState
|
|
14
14
|
from .adk_model import GovernedOpenAiLlm
|
|
15
|
-
from .adk_tools import GovernedTool
|
|
15
|
+
from .adk_tools import ApprovalSignalState, GovernedTool
|
|
16
16
|
from .contracts import JsonValue
|
|
17
17
|
from .engine import (
|
|
18
18
|
AgentEngineAdapter,
|
|
@@ -25,10 +25,11 @@ from .engine import (
|
|
|
25
25
|
ToolRequested,
|
|
26
26
|
UsageReported,
|
|
27
27
|
)
|
|
28
|
+
from .multimodal import final_output
|
|
28
29
|
from .openai_engine import cancelled, validate_runtime_request
|
|
29
30
|
from .openai_provider import OpenAiCompatibleProvider
|
|
30
31
|
from .provider_governance import ProviderRequestGovernance
|
|
31
|
-
from .tool_host import ToolHostClient
|
|
32
|
+
from .tool_host import ToolHostClient, canonical_tool_call_id
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class AdkEngineAdapter(AgentEngineAdapter):
|
|
@@ -45,6 +46,14 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
45
46
|
self._governance = governance
|
|
46
47
|
self._cancellations: dict[str, asyncio.Event] = {}
|
|
47
48
|
|
|
49
|
+
@property
|
|
50
|
+
def capabilities(self) -> tuple[str, ...]:
|
|
51
|
+
return self._provider.config.capabilities if self._provider else ()
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def input_modalities(self) -> tuple[str, ...]:
|
|
55
|
+
return self._provider.config.input_modalities if self._provider else ()
|
|
56
|
+
|
|
48
57
|
def supports(self, operation_key: str) -> bool:
|
|
49
58
|
return bool(operation_key.strip())
|
|
50
59
|
|
|
@@ -53,7 +62,12 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
53
62
|
request: EngineRunRequest,
|
|
54
63
|
) -> AsyncIterator[EngineSignal]:
|
|
55
64
|
provider, tool_host, governance = self._configured()
|
|
56
|
-
validate_runtime_request(
|
|
65
|
+
validate_runtime_request(
|
|
66
|
+
request,
|
|
67
|
+
provider.config.deployment_key,
|
|
68
|
+
provider.config.capabilities,
|
|
69
|
+
provider.config.input_modalities,
|
|
70
|
+
)
|
|
57
71
|
cancellation = self._cancellations.setdefault(
|
|
58
72
|
request.run_id,
|
|
59
73
|
asyncio.Event(),
|
|
@@ -61,7 +75,9 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
61
75
|
output = ""
|
|
62
76
|
output_bytes = 0
|
|
63
77
|
failures = AdkFailureState()
|
|
78
|
+
approvals = ApprovalSignalState()
|
|
64
79
|
event_failure: SafeEngineError | None = None
|
|
80
|
+
tool_call_ids: dict[str, str] = {}
|
|
65
81
|
try:
|
|
66
82
|
session_service = InMemorySessionService() # type: ignore[no-untyped-call]
|
|
67
83
|
await session_service.create_session(
|
|
@@ -88,13 +104,14 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
88
104
|
tool_host,
|
|
89
105
|
cancellation,
|
|
90
106
|
failures,
|
|
107
|
+
approvals,
|
|
91
108
|
)
|
|
92
109
|
for tool in request.allowed_tools
|
|
93
110
|
],
|
|
94
111
|
),
|
|
95
112
|
session_service=session_service,
|
|
96
113
|
)
|
|
97
|
-
|
|
114
|
+
events = runner.run_async(
|
|
98
115
|
user_id="platform",
|
|
99
116
|
session_id=request.run_id,
|
|
100
117
|
new_message=types.Content(
|
|
@@ -105,7 +122,12 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
105
122
|
streaming_mode=StreamingMode.SSE,
|
|
106
123
|
max_llm_calls=provider.config.max_tool_rounds,
|
|
107
124
|
),
|
|
108
|
-
)
|
|
125
|
+
)
|
|
126
|
+
async for item in merge_adk_events(events, approvals.queue):
|
|
127
|
+
if not isinstance(item, Event):
|
|
128
|
+
yield item
|
|
129
|
+
continue
|
|
130
|
+
event = item
|
|
109
131
|
cancelled(cancellation)
|
|
110
132
|
if event.error_code:
|
|
111
133
|
event_failure = failures.failure or SafeEngineError(
|
|
@@ -114,7 +136,11 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
114
136
|
retryable=True,
|
|
115
137
|
)
|
|
116
138
|
continue
|
|
117
|
-
async for signal in signals_for_event(
|
|
139
|
+
async for signal in signals_for_event(
|
|
140
|
+
event,
|
|
141
|
+
request,
|
|
142
|
+
tool_call_ids,
|
|
143
|
+
):
|
|
118
144
|
if isinstance(signal, OutputDelta):
|
|
119
145
|
output_bytes += len(signal.text.encode())
|
|
120
146
|
if output_bytes > request.limits.max_output_bytes:
|
|
@@ -128,7 +154,7 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
128
154
|
if event_failure is not None:
|
|
129
155
|
raise event_failure
|
|
130
156
|
cancelled(cancellation)
|
|
131
|
-
yield EngineCompleted(
|
|
157
|
+
yield EngineCompleted(final_output(output, request.output_schema))
|
|
132
158
|
except SafeEngineError:
|
|
133
159
|
raise
|
|
134
160
|
except asyncio.CancelledError:
|
|
@@ -175,7 +201,11 @@ class AdkEngineAdapter(AgentEngineAdapter):
|
|
|
175
201
|
return self._provider, self._tool_host, self._governance
|
|
176
202
|
|
|
177
203
|
|
|
178
|
-
async def signals_for_event(
|
|
204
|
+
async def signals_for_event(
|
|
205
|
+
event: Event,
|
|
206
|
+
request: EngineRunRequest,
|
|
207
|
+
tool_call_ids: dict[str, str],
|
|
208
|
+
) -> AsyncIterator[EngineSignal]:
|
|
179
209
|
for call in event.get_function_calls():
|
|
180
210
|
if not call.id or not call.name:
|
|
181
211
|
raise SafeEngineError(
|
|
@@ -183,7 +213,14 @@ async def signals_for_event(event: Event) -> AsyncIterator[EngineSignal]:
|
|
|
183
213
|
"模型请求了无效 Tool",
|
|
184
214
|
retryable=False,
|
|
185
215
|
)
|
|
186
|
-
|
|
216
|
+
arguments = call.args if isinstance(call.args, dict) else {}
|
|
217
|
+
stable_id = canonical_tool_call_id(
|
|
218
|
+
request.run_id,
|
|
219
|
+
call.name,
|
|
220
|
+
arguments,
|
|
221
|
+
)
|
|
222
|
+
tool_call_ids[call.id] = stable_id
|
|
223
|
+
yield ToolRequested(stable_id, call.name)
|
|
187
224
|
for response in event.get_function_responses():
|
|
188
225
|
if not response.id:
|
|
189
226
|
raise SafeEngineError(
|
|
@@ -191,7 +228,14 @@ async def signals_for_event(event: Event) -> AsyncIterator[EngineSignal]:
|
|
|
191
228
|
"Agent Tool 响应缺少稳定标识",
|
|
192
229
|
retryable=False,
|
|
193
230
|
)
|
|
194
|
-
|
|
231
|
+
response_tool_call_id = tool_call_ids.get(response.id)
|
|
232
|
+
if not response_tool_call_id:
|
|
233
|
+
raise SafeEngineError(
|
|
234
|
+
"TOOL_DENIED",
|
|
235
|
+
"Agent Tool 响应与请求不匹配",
|
|
236
|
+
retryable=False,
|
|
237
|
+
)
|
|
238
|
+
yield ToolCompleted(response_tool_call_id)
|
|
195
239
|
if event.partial and event.content:
|
|
196
240
|
for part in event.content.parts or []:
|
|
197
241
|
if part.text and not part.thought:
|
|
@@ -212,3 +256,36 @@ def southwind_usage(event: Event) -> dict[str, JsonValue] | None:
|
|
|
212
256
|
if isinstance(key, str)
|
|
213
257
|
and (item is None or isinstance(item, str | int | float | bool | list | dict))
|
|
214
258
|
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
async def merge_adk_events(
|
|
262
|
+
events: AsyncIterator[Event],
|
|
263
|
+
approval_queue: asyncio.Queue[EngineSignal],
|
|
264
|
+
) -> AsyncIterator[Event | EngineSignal]:
|
|
265
|
+
iterator = events.__aiter__()
|
|
266
|
+
event_task: asyncio.Task[Event] = asyncio.create_task(next_event(iterator))
|
|
267
|
+
approval_task = asyncio.create_task(approval_queue.get())
|
|
268
|
+
try:
|
|
269
|
+
while True:
|
|
270
|
+
done, _ = await asyncio.wait(
|
|
271
|
+
{event_task, approval_task},
|
|
272
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
273
|
+
)
|
|
274
|
+
if approval_task in done:
|
|
275
|
+
yield approval_task.result()
|
|
276
|
+
approval_task = asyncio.create_task(approval_queue.get())
|
|
277
|
+
if event_task in done:
|
|
278
|
+
try:
|
|
279
|
+
yield event_task.result()
|
|
280
|
+
except StopAsyncIteration:
|
|
281
|
+
while not approval_queue.empty():
|
|
282
|
+
yield approval_queue.get_nowait()
|
|
283
|
+
return
|
|
284
|
+
event_task = asyncio.create_task(next_event(iterator))
|
|
285
|
+
finally:
|
|
286
|
+
event_task.cancel()
|
|
287
|
+
approval_task.cancel()
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
async def next_event(iterator: AsyncIterator[Event]) -> Event:
|
|
291
|
+
return await iterator.__anext__()
|
|
@@ -13,6 +13,7 @@ from pydantic import PrivateAttr
|
|
|
13
13
|
from .adk_failure import AdkFailureState
|
|
14
14
|
from .contracts import JsonValue
|
|
15
15
|
from .engine import EngineRunRequest, SafeEngineError
|
|
16
|
+
from .multimodal import attach_artifacts
|
|
16
17
|
from .openai_engine import cancelled, parse_arguments
|
|
17
18
|
from .openai_provider import OpenAiCompatibleProvider, ProviderTurn
|
|
18
19
|
from .provider_governance import ProviderRequestGovernance
|
|
@@ -58,7 +59,10 @@ class GovernedOpenAiLlm(BaseLlm):
|
|
|
58
59
|
"Agent Tool 调用轮次超过上限",
|
|
59
60
|
retryable=False,
|
|
60
61
|
)
|
|
61
|
-
messages =
|
|
62
|
+
messages = attach_artifacts(
|
|
63
|
+
adk_messages(llm_request, self._request.instructions),
|
|
64
|
+
self._request.artifacts,
|
|
65
|
+
)
|
|
62
66
|
governed = self._governance.authorize(
|
|
63
67
|
deployment_key=self._provider.config.deployment_key,
|
|
64
68
|
operation_key=self._request.operation_key,
|
|
@@ -68,13 +72,24 @@ class GovernedOpenAiLlm(BaseLlm):
|
|
|
68
72
|
tools=self._request.allowed_tools,
|
|
69
73
|
policy=self._request.provider_data_policy,
|
|
70
74
|
input_value=self._request.input,
|
|
71
|
-
|
|
72
|
-
self.
|
|
75
|
+
artifact_bytes=sum(
|
|
76
|
+
artifact.byte_size for artifact in self._request.artifacts
|
|
77
|
+
),
|
|
78
|
+
output_schema=self._request.output_schema,
|
|
79
|
+
measure=lambda values, tools, schema: len(
|
|
80
|
+
self._provider.request_body(
|
|
81
|
+
values,
|
|
82
|
+
tools,
|
|
83
|
+
self._request.output_schema_key,
|
|
84
|
+
schema,
|
|
85
|
+
)
|
|
73
86
|
),
|
|
74
87
|
)
|
|
75
88
|
turn = await self._provider.complete_turn(
|
|
76
89
|
governed.messages,
|
|
77
90
|
governed.tools,
|
|
91
|
+
self._request.output_schema_key,
|
|
92
|
+
governed.output_schema,
|
|
78
93
|
)
|
|
79
94
|
cancelled(self._cancellation)
|
|
80
95
|
validate_tool_calls(
|
|
@@ -9,9 +9,26 @@ from google.genai import types
|
|
|
9
9
|
|
|
10
10
|
from .adk_failure import AdkFailureState
|
|
11
11
|
from .contracts import JsonValue, RuntimeToolDefinition
|
|
12
|
-
from .engine import
|
|
12
|
+
from .engine import (
|
|
13
|
+
ApprovalRequired,
|
|
14
|
+
ApprovalResolved,
|
|
15
|
+
EngineRunRequest,
|
|
16
|
+
EngineSignal,
|
|
17
|
+
SafeEngineError,
|
|
18
|
+
)
|
|
13
19
|
from .openai_engine import cancelled
|
|
14
|
-
from .tool_host import
|
|
20
|
+
from .tool_host import (
|
|
21
|
+
ToolApprovalPending,
|
|
22
|
+
ToolApprovalResolved,
|
|
23
|
+
ToolHostClient,
|
|
24
|
+
ToolInvocation,
|
|
25
|
+
canonical_tool_call_id,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ApprovalSignalState:
|
|
30
|
+
def __init__(self) -> None:
|
|
31
|
+
self.queue: asyncio.Queue[EngineSignal] = asyncio.Queue()
|
|
15
32
|
|
|
16
33
|
|
|
17
34
|
class GovernedTool(BaseTool):
|
|
@@ -24,6 +41,7 @@ class GovernedTool(BaseTool):
|
|
|
24
41
|
tool_host: ToolHostClient,
|
|
25
42
|
cancellation: asyncio.Event,
|
|
26
43
|
failures: AdkFailureState,
|
|
44
|
+
approvals: ApprovalSignalState,
|
|
27
45
|
) -> None:
|
|
28
46
|
super().__init__(
|
|
29
47
|
name=definition.key,
|
|
@@ -33,6 +51,7 @@ class GovernedTool(BaseTool):
|
|
|
33
51
|
self._tool_host = tool_host
|
|
34
52
|
self._cancellation = cancellation
|
|
35
53
|
self._failures = failures
|
|
54
|
+
self._approvals = approvals
|
|
36
55
|
|
|
37
56
|
def _get_declaration(self) -> types.FunctionDeclaration:
|
|
38
57
|
return types.FunctionDeclaration(
|
|
@@ -59,16 +78,64 @@ class GovernedTool(BaseTool):
|
|
|
59
78
|
"Agent Tool Call 缺少稳定标识",
|
|
60
79
|
retryable=False,
|
|
61
80
|
)
|
|
62
|
-
|
|
63
|
-
self._request.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
81
|
+
stable_call_id = canonical_tool_call_id(
|
|
82
|
+
self._request.run_id,
|
|
83
|
+
self.name,
|
|
84
|
+
cast(dict[str, JsonValue], args),
|
|
85
|
+
)
|
|
86
|
+
invocation = ToolInvocation(
|
|
87
|
+
self._request.run_id,
|
|
88
|
+
stable_call_id,
|
|
89
|
+
self.name,
|
|
90
|
+
cast(dict[str, JsonValue], args),
|
|
91
|
+
self._request.execution_grant,
|
|
71
92
|
)
|
|
93
|
+
approval: ToolApprovalPending | None = None
|
|
94
|
+
while True:
|
|
95
|
+
cancelled(self._cancellation)
|
|
96
|
+
try:
|
|
97
|
+
result = await self._tool_host.execute(
|
|
98
|
+
self._request.tool_host_url,
|
|
99
|
+
invocation,
|
|
100
|
+
)
|
|
101
|
+
if approval:
|
|
102
|
+
await self._approvals.queue.put(
|
|
103
|
+
ApprovalResolved(
|
|
104
|
+
approval.work_item_id,
|
|
105
|
+
stable_call_id,
|
|
106
|
+
"approved",
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
break
|
|
110
|
+
except ToolApprovalPending as pending:
|
|
111
|
+
if approval is None:
|
|
112
|
+
approval = pending
|
|
113
|
+
await self._approvals.queue.put(
|
|
114
|
+
ApprovalRequired(
|
|
115
|
+
pending.work_item_id,
|
|
116
|
+
stable_call_id,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
elif approval.work_item_id != pending.work_item_id:
|
|
120
|
+
raise SafeEngineError(
|
|
121
|
+
"TOOL_DENIED",
|
|
122
|
+
"Agent Tool 审批标识漂移",
|
|
123
|
+
retryable=False,
|
|
124
|
+
) from None
|
|
125
|
+
await asyncio.sleep(2)
|
|
126
|
+
except ToolApprovalResolved as resolved:
|
|
127
|
+
await self._approvals.queue.put(
|
|
128
|
+
ApprovalResolved(
|
|
129
|
+
resolved.work_item_id,
|
|
130
|
+
stable_call_id,
|
|
131
|
+
resolved.outcome,
|
|
132
|
+
)
|
|
133
|
+
)
|
|
134
|
+
raise SafeEngineError(
|
|
135
|
+
"TOOL_DENIED",
|
|
136
|
+
"Agent Tool 审批未通过",
|
|
137
|
+
retryable=False,
|
|
138
|
+
) from None
|
|
72
139
|
cancelled(self._cancellation)
|
|
73
140
|
return result
|
|
74
141
|
except SafeEngineError as error:
|