refactor(managed-agent): organize server packages by responsibility (#14710)

This commit is contained in:
jinye authored and GitHub committed 2026-10-19 14:16:18 +00:00
1 parent fc67c01dad
commit 2197d02941
676 files changed
+5306 -4296

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@ does not contact the cluster or database. From the server package, invoke the
built operator with:
```bash
java -Dloader.main=com.alibaba.qwen.code.managedagent.service.WorkspaceCsiProtectionMain \
java -Dloader.main=com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiProtectionMain \
-cp target/qwen-managed-agent-server-0.1.0-alpha-csi-runtime.jar \
org.springframework.boot.loader.launch.PropertiesLauncher \
/absolute/path/registration.json resident-protection resident-binding
+1 -1
View File
@@ -26,7 +26,7 @@ Kubernetes JSON List,不访问集群或数据库。在 server 包目录中调
operator:
```bash
java -Dloader.main=com.alibaba.qwen.code.managedagent.service.WorkspaceCsiProtectionMain \
java -Dloader.main=com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiProtectionMain \
-cp target/qwen-managed-agent-server-0.1.0-alpha-csi-runtime.jar \
org.springframework.boot.loader.launch.PropertiesLauncher \
/absolute/path/registration.json resident-protection resident-binding
@@ -97,7 +97,7 @@ MQ wake claims use the same durable legacy-mutation guard before inserting or ad
Ordinary publication refuses private Sessions when allocating a read lease or PUT attempt. Session profile and request pin are fixed at creation; supported APIs never convert an ordinary Session into a private Session. Admitted leases continue checking expiration and retirement, and close only removes that lease. Admitted PUTs must record RETURNED or UNKNOWN without losing physical-write evidence to another admission check. These settlement operations do not need another journal-head lock. Collector guards and lock order remain intact. Main's budget assertions are unchanged: 4 statements for an empty materialization tick, 35 for a full batch and 17 for its tail, and 6 locked head reads in the exercised publication path.
Broker and Server share the identity implementation. The former `com.alibaba.qwen.code.managedagent.service.WorkspaceCsiRuntimeIdentity` retains its public static `verify`, `boot` and `expectedPod` methods, delegating to Broker. The former entry point is deprecated without duplicating validation logic. The added Broker API and feature still require maintainer review.
Broker and Server share the identity implementation. The Spring adapter `com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiRuntimeIdentity` retains its public static `verify`, `boot` and `expectedPod` methods, delegating to Broker. The adapter is deprecated without duplicating validation logic. The added Broker API and feature still require maintainer review.
Integration with main retains ordinary Monitor control classification, exact watch ownership, exit-evidence settlement and hold-row fencing. Private CSI history dispatch still requires the original READY owner and its own control fence. Every generic control, including Monitor, refuses a private CSI Runtime before transport. These are separate existing paths; the integration adds no private Monitor or Hosted entry point.
@@ -84,7 +84,7 @@ MQ wake claim 在插入或推进 `journal_wake` 进度、调度 Hosted activatio
普通 publication 在分配读取租约和 PUT attempt 时拒绝私有 Session。Session 的 profile 与请求 pin 在创建时确定,支持的 API 不会将普通 Session 转换为私有 Session。已准入租约继续检查到期与退役,close 只清除该租约;已准入 PUT 必须记录 RETURNED 或 UNKNOWN,不能因再次准入而丢失物理写入证据。这些收尾操作无需再次锁 journal head。collector 的私有检查和锁顺序继续保留。主干的预算断言不变:空 materialize tick 为 4 条语句,完整批次为 35 条、末批为 17 条,受测 publish 路径为 6 次 head 加锁读取。
身份实现由 Broker 与 Server 共享;旧 `com.alibaba.qwen.code.managedagent.service.WorkspaceCsiRuntimeIdentity` 保留已公开的 `verify`、`boot` 与 `expectedPod` 静态方法,并委托给 Broker 实现。旧入口标记为 deprecated,不复制身份验证逻辑。新增的 Broker API 与本 feature 仍需 maintainer 评审。
身份实现由 Broker 与 Server 共享;Spring 适配器 `com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiRuntimeIdentity` 保留已公开的 `verify`、`boot` 与 `expectedPod` 静态方法,并委托给 Broker 实现。该适配器标记为 deprecated,不复制身份验证逻辑。新增的 Broker API 与本 feature 仍需 maintainer 评审。
与主干整合时保留普通 Monitor control 分类、准确 watch ownership、exit-evidence 收尾与 hold-row 栅栏。私有 CSI history dispatch 继续要求原 READY owner 及独立 control 栅栏。所有通用 control(包括 Monitor)在 transport 前拒绝私有 CSI Runtime。这是两条既有路径,整合不新增私有 Monitor 或 Hosted 入口。
@@ -0,0 +1,84 @@
# Managed Agent Server package boundaries
[English](2026-10-19-managed-agent-package-boundaries.md) | [简体中文](2026-10-19-managed-agent-package-boundaries.zh-CN.md)
Status: implemented and verified locally on main base `f37e003d9450`. Remote CI and formal review are tracked on [PR #14710](https://github.com/QwenLM/qwen-code/pull/14710). The optional MySQL, Hosted and Linux fault profiles were not run locally for this package reorganization.
## Problem and current state
Managed Agent Server is one Spring Boot application and Maven module. Before this change, its `service` and `store` packages contained unrelated business capabilities, while application and persistence code imported request models, tenant context, Workspace selection and exceptions from `api`. Runtime Broker combined its orchestration, providers and HTTP adapters in one package. This made responsibility and dependency direction difficult to see.
The existing [source-layout decision](2026-10-15-managed-agent-server-layout.md) remains valid: the Broker does not need a separately published artifact for its single production consumer. This change organizes Java packages inside that application.
## Goals and scope
- Keep one Maven module and one service deployment.
- Remove application and persistence dependencies on the HTTP controller package.
- Group Session, Workspace, Artifact, Channel, Automation, catalog and event components by responsibility.
- Separate Broker provisioning, transport and credential protection from its execution and repository core.
- Preserve HTTP contracts, authentication, SQL bytes, transaction boundaries, persisted identities and recovery behavior.
This is a source organization change. It does not redesign persistence, introduce new service interfaces, split the deployment, or change the maintenance application's component-scan boundary.
## Proposed structure
```text
com.alibaba.qwen.code
├── managedagent
│ ├── api HTTP controllers, filters and response mapping
│ ├── model Shared request/response and stored value types
│ ├── exception Shared application errors
│ ├── security Writer credentials and route policy
│ ├── session Session and command orchestration
│ ├── workspace Workspace services and selection
│ │ └── runtime Workspace runtime integration and recovery commands
│ ├── artifact Artifact access and object-storage contracts
│ ├── channel Channel service and adapter models
│ ├── automation Scheduling and automation service
│ ├── catalog Agent definitions, skills, hooks and MCP catalogs
│ ├── event Committed event publication and delivery
│ ├── persistence Shared SQL aggregate and transaction implementation
│ ├── harness Hosted Harness integration
│ ├── config Spring configuration
│ └── preflight Startup checks
├── runtimebroker
│ ├── provisioning Physical runtime providers and provider protocols
│ ├── transport Runtime HTTP transport and wire protocols
│ ├── security Credential encryption
│ ├── managedschema Shared database schema
│ └── managedworkspace Workspace contracts
└── maintenance Independently configured maintenance application
```
## Decisions and constraints
Request/response records and validation annotations move together without changing JSON names, deserializers or validation. The shared application exception keeps its existing status, code, details and cause semantics; only its name and ownership change. HTTP error-envelope translation remains in `api`.
Session, Workspace and publication persistence share package-private transaction operations. Keep that aggregate in one `persistence` package rather than exposing its locks and mutation helpers to divide it by business labels. Independent object-storage contracts and event interfaces move to their owning capability. Move canonical request digests out of the former service package so persistence can use the same digest implementation.
Broker providers and transports use existing protocol validators and value operations. Expose only the existing members consumed across the new package boundaries. Keep local-process state and SQL implementation helpers package-private. Update tests to follow the package whose internals they exercise; avoid making production internals public solely for a test. Two test-only access fixtures forward existing Broker-core and HTTP-transport seams across packages without exposing those production internals.
Broker-core repositories use `transport.ManagedHoldFamily` to classify stored dispatch modes. Its dispatch-mode lookup is public for that core consumer, and `ToolHoldRow` stays in the core with the inventory repositories. Rebase validation compiles the updated core and transport consumers together.
Keep the server's Spring Boot application at its existing root and the maintenance configuration outside that root. Update imports, fully qualified names, launcher configuration, current documentation links and any source-file references together. Preserve resource paths, Maven test profiles, fault gates and the Broker's separate Checkstyle execution.
## Risks and validation
The principal risks are implicit same-package references, accidental Spring component discovery changes, stale command entry points, test helpers that rely on package access and incomplete documentation links. Inventory all production and test classes before and after the move, compile all sources, run affected tests and full Maven verification with JDK 21, and inspect the packaged application. Build the Java SDK from this checkout and prepare Core/CLI outputs for native conformance tests.
Compare source bodies after normalizing package names, imports and required visibility changes. Check that application and persistence packages no longer import `managedagent.api`, Broker remains independent of Spring and control-plane classes, and SQL/OpenAPI resources are unchanged. Run formatting, reference checks and two clean self-audit passes. Report skipped environment-specific profiles separately; ordinary Java tests do not establish MySQL or Linux recovery acceptance.
Local verification with JDK 21 passed:
- `mvn clean verify`: 4,796 tests, zero failures/errors and 18 existing skips; both Checkstyle executions and SpotBugs reported zero findings. All existing Maven verification gates remain enabled.
- Root `npm run build` and `npm run typecheck`, all 39 affected script tests, targeted ESLint, and Javadoc reference checks passed.
- All 322 production source bodies are unchanged after namespace/import/visibility normalization. All 877 compiled classes and 16,860 declaration signatures are retained, with no reduction of existing public access.
- All seven executable JARs contain the expected entry points and unchanged resources. Four maintenance entry points reject empty arguments before file, database or cloud access.
## Acceptance criteria
All original classes and resources remain present under their new ownership, existing routes and wire contracts pass their regression tests, and standard Maven verification passes without disabling a gate. Shared SQL transaction helpers retain their package access. Application and persistence code have no imports from the controller package. Both design documents and current build/maintenance instructions reflect the final structure.
## Open questions
None for this package reorganization. A later independent consumer or a concrete need for compilation isolation can justify Maven modules.
@@ -0,0 +1,84 @@
# Managed Agent Server 包边界
[English](2026-10-19-managed-agent-package-boundaries.md) | [简体中文](2026-10-19-managed-agent-package-boundaries.zh-CN.md)
状态:已在主干基点 `f37e003d9450` 上实现并完成本地验证。远端 CI 与正式评审状态见 [PR #14710](https://github.com/QwenLM/qwen-code/pull/14710)。本次包调整未在本地运行可选的 MySQL、Hosted 和 Linux 故障专项 profile。
## 问题与现状
Managed Agent Server 是一个 Spring Boot 应用和 Maven 模块。调整前,`service` 和 `store` 包混合了多个业务能力,应用与持久化代码还从 `api` 引用请求模型、租户上下文、Workspace 选择及异常。Runtime Broker 则将编排、供应器和 HTTP 适配器放在同一个包中,难以直接看出职责和依赖方向。
既有[源码布局决策](2026-10-15-managed-agent-server-layout.zh-CN.md)仍然适用:Broker 只有一个生产消费方,无需为此单独发布产物。本次调整应用内部的 Java 包组织。
## 目标与范围
- 保留一个 Maven 模块和一个服务部署。
- 消除应用与持久化代码对 HTTP 控制器包的依赖。
- 按职责组织 Session、Workspace、Artifact、Channel、Automation、目录和事件组件。
- 将 Broker 的供应、传输和凭据保护与执行及仓储核心分开。
- 保留 HTTP 契约、认证、SQL 字节、事务边界、持久化身份和恢复行为。
本次仅调整源码组织,不重新设计持久化,不引入新的服务接口,不拆分部署,也不改变维护应用的组件扫描边界。
## 目标结构
```text
com.alibaba.qwen.code
├── managedagent
│ ├── api HTTP 控制器、过滤器与响应映射
│ ├── model 共享请求响应与存储值类型
│ ├── exception 共享应用异常
│ ├── security Writer 凭据与路由策略
│ ├── session Session 与命令编排
│ ├── workspace Workspace 服务与选择
│ │ └── runtime Workspace Runtime 集成与恢复命令
│ ├── artifact 产物访问与对象存储契约
│ ├── channel Channel 服务与适配器模型
│ ├── automation 调度与自动化服务
│ ├── catalog Agent 定义、Skill、Hook 和 MCP 目录
│ ├── event 已提交事件的发布与投递
│ ├── persistence 共享 SQL 聚合与事务实现
│ ├── harness Hosted Harness 接入
│ ├── config Spring 配置
│ └── preflight 启动检查
├── runtimebroker
│ ├── provisioning 物理 Runtime 供应器及供应协议
│ ├── transport Runtime HTTP 传输与线上协议
│ ├── security 凭据加密
│ ├── managedschema 共享数据库结构
│ └── managedworkspace Workspace 契约
└── maintenance 独立配置的维护应用
```
## 决策与约束
请求响应记录与校验注解一起迁移,不改变 JSON 名称、反序列化器或校验规则。共享应用异常保留现有状态、错误码、详情和 cause 语义,只调整名称与归属。HTTP 错误信封映射仍放在 `api`。
Session、Workspace 和发布持久化共享包内事务操作。将该聚合保留在同一个 `persistence` 包中,不为按业务名称拆包而公开锁及变更辅助方法。独立的对象存储契约和事件接口归入对应能力。将规范请求摘要移出原服务包,让持久化继续复用同一份摘要实现。
Broker 供应器和传输组件复用现有协议校验及值操作,只公开新包边界实际需要访问的既有成员。本地进程状态与 SQL 实现辅助类保留包内可见性。测试跟随其实际验证的内部实现所在包,不仅为了测试而公开生产代码内部成员。两个仅供测试使用的访问夹具跨包转发现有 Broker 核心与 HTTP 传输访问点,避免公开对应的生产代码内部成员。
Broker 核心仓储通过 `transport.ManagedHoldFamily` 识别已存储的 dispatch mode。该查询对跨包的核心消费方公开;`ToolHoldRow` 与相关仓储保留在核心包。变基验证需要一起编译更新后的核心与传输层消费方。
保留服务端 Spring Boot 应用原有根包,维护配置继续位于该根包之外。同时更新 import、完整类名、启动配置、当前文档链接和源码文件引用。保留资源路径、Maven 测试 profile、故障门禁及 Broker 单独的 Checkstyle 执行。
## 风险与验证
主要风险是隐式同包引用、Spring 组件发现意外变化、命令入口残留旧名称、测试辅助代码依赖包内访问,以及文档链接更新不完整。迁移前后核对全部生产与测试类清单,编译所有源码,使用 JDK 21 运行相关测试和完整 Maven 验证,并检查打包应用。Java SDK 使用当前检出源码构建,同时准备原生一致性测试所需的 Core/CLI 输出。
规范化包名、import 和必要可见性变化后,对比源码主体。检查应用与持久化包不再引用 `managedagent.api`,Broker 继续独立于 Spring 和控制面类,SQL/OpenAPI 资源保持不变。执行格式、引用检查及两遍干净自审。单独报告未运行的环境专用 profile,普通 Java 测试不代表 MySQL 或 Linux 恢复验收。
JDK 21 本地验证通过:
- `mvn clean verify`:4,796 项测试,零失败、零错误,18 项既有跳过;两项 Checkstyle 执行和 SpotBugs 均为零问题。全部既有 Maven 验证门禁保持开启。
- 根目录 `npm run build`、`npm run typecheck`、全部 39 项相关脚本测试、针对性 ESLint 和 Javadoc 引用检查均通过。
- 规范化包名、import 和可见性后,全部 322 个生产源码主体保持不变。全部 877 个编译类及 16,860 个声明签名完整保留,既有公开访问权限没有收窄。
- 7 个可执行 JAR 均包含预期入口和未变的资源。4 个维护入口在访问文件、数据库或云服务之前正确拒绝空参数。
## 验收标准
所有原有类和资源按新归属完整保留,既有路由与线上契约通过回归测试,标准 Maven 验证通过且未关闭门禁。共享 SQL 事务辅助代码保留包内可见性。应用与持久化代码不从控制器包导入类型。两份设计文档及当前构建、维护说明反映最终结构。
## 待定问题
本次包调整没有待定问题。后续出现独立消费方或明确的编译隔离需求时,再评估 Maven 多模块。
+2 -2
View File
@@ -26,7 +26,7 @@ The probe exited 0 because its refusal/control assertions passed. This is not a
## Publication prerequisite
Production [publication configuration](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/config/ToolPublicationConfiguration.java) is disabled by default. Enabling it requires explicit capacity/deadline budgets and a real regional HTTPS OSS endpoint, region, private bucket without versioning and configured credentials. The [OSS object store constructor](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/store/AliyunToolPublicationObjectStore.java) validates bucket versioning and ACL even before a small inline-output control can run.
Production [publication configuration](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/config/ToolPublicationConfiguration.java) is disabled by default. Enabling it requires explicit capacity/deadline budgets and a real regional HTTPS OSS endpoint, region, private bucket without versioning and configured credentials. The [OSS object store constructor](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/artifact/AliyunToolPublicationObjectStore.java) validates bucket versioning and ACL even before a small inline-output control can run.
No explicit Managed Agent test bucket/namespace or publication configuration was found in the bounded acceptance configuration search. General cloud login profiles are not evidence of an approved test bucket. No cloud credentials were copied to the VM or used for this probe.
@@ -91,7 +91,7 @@ Broker、Spring SQL Store、打包 CLI 与 Runtime worker 均为真实进程;
## Publication 前置条件
生产 [publication 配置](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/config/ToolPublicationConfiguration.java)默认关闭。启用要求显式容量/时限预算、真实区域 HTTPS OSS endpoint、region、私有且未开启版本控制的 bucket,以及配置好的凭据。[OSS 对象存储构造器](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/store/AliyunToolPublicationObjectStore.java)会先校验 bucket 版本控制与 ACL,即使只想跑小型 inline-output 控制也一样。
生产 [publication 配置](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/config/ToolPublicationConfiguration.java)默认关闭。启用要求显式容量/时限预算、真实区域 HTTPS OSS endpoint、region、私有且未开启版本控制的 bucket,以及配置好的凭据。[OSS 对象存储构造器](../../../packages/managed-agent-server/src/main/java/com/alibaba/qwen/code/managedagent/artifact/AliyunToolPublicationObjectStore.java)会先校验 bucket 版本控制与 ACL,即使只想跑小型 inline-output 控制也一样。
限定范围的验收配置搜索未找到明确的 Managed Agent 测试 bucket/namespace 或 publication 配置。一般云登录 profile 不能证明某 bucket 已指定用于测试。本次没有向 VM 复制或使用云凭据。
+17 -2
View File
@@ -16,6 +16,21 @@ authentication and writer credentials" below.
设计说明:[English](../../docs/design/2026-09-19-managed-agent-spring-server.md) |
[简体中文](../../docs/design/2026-09-19-managed-agent-spring-server.zh-CN.md)
## Java package layout
Business components live in `managedagent.session`, `workspace`, `artifact`,
`channel`, `automation`, `catalog` and `event`. Controllers and HTTP filters
remain in `managedagent.api`; shared contracts and application errors live in
`managedagent.model` and `exception`. The shared SQL aggregate remains in
`managedagent.persistence` so its transaction and locking helpers stay
package-private. Broker providers, HTTP adapters and credential protection live
in `runtimebroker.provisioning`, `transport` and `security` respectively. The
separate `maintenance` configuration remains outside the server's component scan.
These are packages in one Maven module. See the package-boundary design:
[English](../../docs/design/2026-10-19-managed-agent-package-boundaries.md) |
[简体中文](../../docs/design/2026-10-19-managed-agent-package-boundaries.zh-CN.md).
## Integration status
The Hosted path supports durable no-tool Sessions and private Workspace tool
@@ -1195,7 +1210,7 @@ crash. Database credentials come from `W1_JDBC_URL`, `W1_JDBC_USER` and
```bash
mvn -q -DskipTests compile exec:java \
-Dexec.mainClass=com.alibaba.qwen.code.managedagent.store.WorkspaceStorageRegistrationMain \
-Dexec.mainClass=com.alibaba.qwen.code.managedagent.persistence.WorkspaceStorageRegistrationMain \
-Dexec.args='register tenant-a storage-a /absolute/canonical/workspace-a <operation-uuid> --offline-confirmed'
```
@@ -1203,7 +1218,7 @@ The same entry is available from a shipped Spring Boot fat jar, without the sour
```bash
java -cp /path/to/app.jar \
-Dloader.main=com.alibaba.qwen.code.managedagent.store.WorkspaceStorageRegistrationMain \
-Dloader.main=com.alibaba.qwen.code.managedagent.persistence.WorkspaceStorageRegistrationMain \
org.springframework.boot.loader.launch.PropertiesLauncher \
register tenant-a storage-a /absolute/canonical/workspace-a '<operation-uuid>' --offline-confirmed
```
@@ -7,6 +7,11 @@ and JDBC implementations; and a framework-neutral service that composes
authoritative scope resolution, Runtime provisioning, and Runtime transport
adapters.
Runtime providers and their deployment protocols are in `runtimebroker.provisioning`,
HTTP adapters and wire protocols in `runtimebroker.transport`, and credential
encryption in `runtimebroker.security`. The execution and repository core stays
in the parent package; the application still builds all of them in one Maven module.
The service acquires operation and dispatch leases, renews them while external
work is in flight, converges idempotent Tool execution, records cancellation
intent, and fails ambiguous dispatch outcomes as `UNKNOWN`.
+6 -6
View File
@@ -144,7 +144,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>workspace-bundle</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.store.WorkspaceRecoveryMain</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.persistence.WorkspaceRecoveryMain</mainClass>
</configuration>
</execution>
<execution>
@@ -152,7 +152,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>workspace-migration</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.service.WorkspaceMigrationMain</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceMigrationMain</mainClass>
</configuration>
</execution>
<execution>
@@ -160,7 +160,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>workspace-maintenance-recovery</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.store.WorkspaceMaintenanceRecoveryMain</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.persistence.WorkspaceMaintenanceRecoveryMain</mainClass>
</configuration>
</execution>
<execution>
@@ -168,7 +168,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>csi-session</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.store.WorkspaceCsiSessionMain</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.persistence.WorkspaceCsiSessionMain</mainClass>
</configuration>
</execution>
<execution>
@@ -176,7 +176,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>csi-runtime</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.store.WorkspaceCsiRuntimeMain</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.persistence.WorkspaceCsiRuntimeMain</mainClass>
</configuration>
</execution>
<execution>
@@ -184,7 +184,7 @@
<goals><goal>repackage</goal></goals>
<configuration>
<classifier>operator-recovery</classifier>
<mainClass>com.alibaba.qwen.code.managedagent.service.WorkspaceRecoveryCommand</mainClass>
<mainClass>com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceRecoveryCommand</mainClass>
</configuration>
</execution>
</executions>
@@ -1,9 +1,10 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AgentDefinition;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AgentDefinitionRequest;
import com.alibaba.qwen.code.managedagent.service.ManagedAgentDefinitionService;
import com.alibaba.qwen.code.managedagent.service.ManagedAgentDefinitionService.Result;
import com.alibaba.qwen.code.managedagent.catalog.ManagedAgentDefinitionService;
import com.alibaba.qwen.code.managedagent.catalog.ManagedAgentDefinitionService.Result;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AgentDefinition;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AgentDefinitionRequest;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -1,6 +1,8 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationStorageException;
import com.alibaba.qwen.code.managedagent.artifact.ToolPublicationStorageException;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.security.PublicSurface;
import com.alibaba.qwen.code.runtimebroker.RuntimeBrokerException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -38,8 +40,8 @@ public class ApiExceptionHandler {
private static final int LOGGED_FRAMES = 6;
private static final int LOGGED_URI_CHARS = 256;
@ExceptionHandler(ApiException.class)
public ResponseEntity<Map<String, Object>> api(ApiException error,
@ExceptionHandler(ManagedAgentException.class)
public ResponseEntity<Map<String, Object>> api(ManagedAgentException error,
HttpServletRequest request, HttpServletResponse response) {
return response(request, response, error.getStatus(), error.getCode(),
error.getMessage(), error.getDetails());
@@ -1,14 +1,15 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PermissionResponse;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicActionList;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicCommandOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellActionGetRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellActionQueryRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellActionRespondRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellCommandOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.service.ManagedActionService;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PermissionResponse;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicActionList;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicCommandOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellActionGetRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellActionQueryRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellActionRespondRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellCommandOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.session.ManagedActionService;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -1,13 +1,14 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ArtifactResponse;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ToolResultResponse;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellArtifactQueryRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellArtifactRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellToolResultRequest;
import com.alibaba.qwen.code.managedagent.service.ManagedArtifactService;
import com.alibaba.qwen.code.managedagent.artifact.ManagedArtifactService;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ArtifactResponse;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ToolResultResponse;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellArtifactQueryRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellArtifactRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellToolResultRequest;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
@@ -1,11 +1,12 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AutomationDefinitionRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicAutomation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicAutomationRun;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.service.ManagedAutomationService;
import com.alibaba.qwen.code.managedagent.service.ManagedAutomationService.Result;
import com.alibaba.qwen.code.managedagent.automation.ManagedAutomationService;
import com.alibaba.qwen.code.managedagent.automation.ManagedAutomationService.Result;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AutomationDefinitionRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicAutomation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicAutomationRun;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -1,15 +1,16 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ChannelInstanceView;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ClaimRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ClaimResponse;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.DeliveryView;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.InboundAdmission;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.InboundEventRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ReceiptRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.RegisterChannelRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ResendResponse;
import com.alibaba.qwen.code.managedagent.service.ManagedChannelService;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ChannelInstanceView;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ClaimRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ClaimResponse;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.DeliveryView;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.InboundAdmission;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.InboundEventRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ReceiptRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.RegisterChannelRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ResendResponse;
import com.alibaba.qwen.code.managedagent.channel.ManagedChannelService;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.validation.Valid;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.web.bind.annotation.PathVariable;
@@ -1,9 +1,10 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicChannel;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicChannelDelivery;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.service.ManagedChannelService;
import com.alibaba.qwen.code.managedagent.channel.ManagedChannelService;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicChannel;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicChannelDelivery;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.service.ManagedHookCatalogService;
import com.alibaba.qwen.code.managedagent.catalog.ManagedHookCatalogService;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.service.ManagedMcpCatalogService;
import com.alibaba.qwen.code.managedagent.catalog.ManagedMcpCatalogService;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
@@ -1,21 +1,23 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.AcquireWriterRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.BlockRecoveryRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.CommitReceipt;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.CommitTransactionRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.PublishToolResultRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.RecoveryStateReceipt;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.RenewWriterRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.RestoreHead;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.SealReceipt;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.SealWriterRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.ToolResultResourceRef;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.TransactionPage;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.WriterGrant;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.AcquireWriterRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.BlockRecoveryRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.CommitReceipt;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.CommitTransactionRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.PublishToolResultRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.RecoveryStateReceipt;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.RenewWriterRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.RestoreHead;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.SealReceipt;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.SealWriterRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.ToolResultResourceRef;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.TransactionPage;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.WriterGrant;
import jakarta.validation.Valid;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpHeaders;
@@ -50,7 +52,7 @@ public class ManagedSessionStoreController {
try {
return new com.alibaba.qwen.code.runtimebroker.RuntimeLifecycleAuthority(operation, Long.parseLong(generation));
} catch (RuntimeException error) {
throw new ApiException(org.springframework.http.HttpStatus.BAD_REQUEST, "invalid_lifecycle_authority", "Invalid lifecycle authority.");
throw new ManagedAgentException(org.springframework.http.HttpStatus.BAD_REQUEST, "invalid_lifecycle_authority", "Invalid lifecycle authority.");
}
}
@@ -1,8 +1,9 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellToolDetails;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellToolResultRequest;
import com.alibaba.qwen.code.managedagent.service.ManagedToolDetailsService;
import com.alibaba.qwen.code.managedagent.artifact.ManagedToolDetailsService;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellToolDetails;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellToolResultRequest;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
@@ -1,25 +1,28 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ChangeCwdRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.api.ApiModels.CreateSessionRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicCommandOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicCwdOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicItemList;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicSession;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicTask;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicTaskEvent;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicTurn;
import com.alibaba.qwen.code.managedagent.api.ApiModels.SessionEventRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.UpdateSessionRequest;
import com.alibaba.qwen.code.managedagent.service.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.service.ManagedAgentService.SessionMutationResult;
import com.alibaba.qwen.code.managedagent.service.ManagedEventStreamService;
import com.alibaba.qwen.code.managedagent.service.ManagedTaskCancelService;
import com.alibaba.qwen.code.managedagent.service.ManagedTaskService;
import com.alibaba.qwen.code.managedagent.service.SessionLifecycleService;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ChangeCwdRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.model.ApiModels.CreateSessionRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicCommandOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicCwdOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicItemList;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicSession;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicTask;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicTaskEvent;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicTurn;
import com.alibaba.qwen.code.managedagent.model.ApiModels.SessionEventRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.UpdateSessionRequest;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService.SessionMutationResult;
import com.alibaba.qwen.code.managedagent.session.ManagedEventStreamService;
import com.alibaba.qwen.code.managedagent.session.ManagedTaskCancelService;
import com.alibaba.qwen.code.managedagent.session.ManagedTaskService;
import com.alibaba.qwen.code.managedagent.session.SessionLifecycleService;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceSelection;
import jakarta.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
@@ -64,14 +67,14 @@ public class PublicAgentController {
WorkspaceSelection selection = null;
if (request.workspace() != null) {
if (request.workspace().isNull()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_request", "Workspace cannot be null.");
}
selection = WorkspaceSelection.parse(request.workspace(), false);
tenant.requireActorId();
}
if (Boolean.TRUE.equals(request.stream())) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_feature",
"Phase 1 streams through the Session events route.");
}
@@ -179,7 +182,7 @@ public class PublicAgentController {
request.admissionProfile());
} else if ("agent.session.cancel".equals(request.type())) {
if (request.turnId() == null || request.turnId().isBlank()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"turn_id_required",
"Cancellation requires turn_id.");
}
@@ -187,7 +190,7 @@ public class PublicAgentController {
idempotencyKey, sessionId, request.turnId(),
request.admissionProfile());
} else {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_event",
"Phase 1 accepts input message and cancellation events.");
}
@@ -228,7 +231,7 @@ public class PublicAgentController {
try {
sequence = Long.parseLong(after);
} catch (NumberFormatException error) {
throw new ApiException(
throw new ManagedAgentException(
org.springframework.http.HttpStatus.BAD_REQUEST,
"invalid_event_cursor",
"Item sequence is invalid.");
@@ -301,7 +304,7 @@ public class PublicAgentController {
}
return value;
} catch (NumberFormatException error) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_event_cursor", "Last-Event-ID is invalid.");
}
}
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.config.BrokerSecurity;
import com.alibaba.qwen.code.managedagent.security.PublicSurface;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -1,9 +1,10 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.service.SshWorkspaceService;
import com.alibaba.qwen.code.managedagent.service.SshWorkspaceService.Directory;
import com.alibaba.qwen.code.managedagent.service.SshWorkspaceService.NodePage;
import com.alibaba.qwen.code.managedagent.store.SshWorkspaceStore.Operation;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.SshWorkspaceStore.Operation;
import com.alibaba.qwen.code.managedagent.workspace.SshWorkspaceService;
import com.alibaba.qwen.code.managedagent.workspace.SshWorkspaceService.Directory;
import com.alibaba.qwen.code.managedagent.workspace.SshWorkspaceService.NodePage;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
@@ -1,5 +1,6 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
@@ -1,5 +1,7 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.security.PublicSurface;
import com.alibaba.qwen.code.runtimebroker.managedworkspace.WorkspaceActor;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
@@ -1,12 +1,14 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.CommitTransactionRequest;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationAdmissionStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationContract;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationStore;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.CommitTransactionRequest;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationAdmissionStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationContract;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationStore;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
@@ -244,7 +246,7 @@ public class ToolPublicationController {
private <T> T limited(Supplier<T> operation) {
if (!entries.tryAcquire()) {
throw new ApiException(HttpStatus.TOO_MANY_REQUESTS,
throw new ManagedAgentException(HttpStatus.TOO_MANY_REQUESTS,
"managed_tool_publication_busy", "Tool publication entry capacity is exhausted");
}
try {
@@ -258,7 +260,7 @@ public class ToolPublicationController {
try {
byte[] body = request.getInputStream().readNBytes(maximum + 1);
if (body.length > maximum) {
throw new ApiException(HttpStatus.PAYLOAD_TOO_LARGE,
throw new ManagedAgentException(HttpStatus.PAYLOAD_TOO_LARGE,
"managed_tool_publication_too_large", "Tool publication body exceeds its limit");
}
return body;
@@ -275,7 +277,7 @@ public class ToolPublicationController {
private static void requireScope(TenantContext tenant, String sessionId, JsonNode key) {
if (!tenant.tenantId().equals(key.path("tenantId").asText())
|| !sessionId.equals(key.path("sessionId").asText())) {
throw new ApiException(HttpStatus.NOT_FOUND,
throw new ManagedAgentException(HttpStatus.NOT_FOUND,
"managed_tool_publication_scope", "Publication Session scope conflicts");
}
}
@@ -1,40 +1,44 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellAdmission;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellCancelRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellChangeCwdRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellChangeModelRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellCommandOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellCreateRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellCwdOperation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellLifecycleRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellListRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelChangeResult;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellOperationRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSession;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionModels;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionModelsRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionOptions;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionOptionsRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellStreamRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSubmitRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTask;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTaskCancelRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTaskEvent;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTaskEventQueryRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTaskGetRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTaskQueryRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTranscript;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellTranscriptRequest;
import com.alibaba.qwen.code.managedagent.service.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.service.ManagedEventStreamService;
import com.alibaba.qwen.code.managedagent.service.ManagedTaskCancelService;
import com.alibaba.qwen.code.managedagent.service.ManagedTaskService;
import com.alibaba.qwen.code.managedagent.service.SessionLifecycleService;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels;
import com.alibaba.qwen.code.managedagent.model.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellAdmission;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellCancelRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellChangeCwdRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellChangeModelRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellCommandOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellCreateRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellCwdOperation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellLifecycleRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellListRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelChangeResult;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellOperationRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSession;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionModels;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionModelsRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionOptions;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionOptionsRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellStreamRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSubmitRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTask;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTaskCancelRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTaskEvent;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTaskEventQueryRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTaskGetRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTaskQueryRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTranscript;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellTranscriptRequest;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.session.ManagedEventStreamService;
import com.alibaba.qwen.code.managedagent.session.ManagedTaskCancelService;
import com.alibaba.qwen.code.managedagent.session.ManagedTaskService;
import com.alibaba.qwen.code.managedagent.session.SessionLifecycleService;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceSelection;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
@@ -148,7 +152,7 @@ public class WebShellAgentController {
WorkspaceSelection selection = null;
if (request.workspace() != null) {
if (request.workspace().isNull()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_request", "Workspace cannot be null.");
}
selection = WorkspaceSelection.parse(request.workspace(), true);
@@ -156,12 +160,12 @@ public class WebShellAgentController {
}
if (request.environmentId() != null
&& !request.environmentId().isBlank()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_feature",
"Standalone Phase 1 has no environment templates.");
}
if (selection == null && (request.approvalMode() != null || request.planMode() != null)) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_approval_mode",
"Approval mode selection requires a bound Workspace.");
}
@@ -1,8 +1,9 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionSkills;
import com.alibaba.qwen.code.managedagent.service.ManagedSkillCatalogService;
import com.alibaba.qwen.code.managedagent.catalog.ManagedSkillCatalogService;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionSkills;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import jakarta.validation.Valid;
import org.springframework.http.CacheControl;
import org.springframework.http.ResponseEntity;
@@ -1,9 +1,10 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.service.WorkspaceDiscoveryService;
import com.alibaba.qwen.code.managedagent.service.WorkspaceDiscoveryService.WorkspacePage;
import com.alibaba.qwen.code.managedagent.store.ManagedWorkspaceRegistry.WorkspaceSummary;
import com.alibaba.qwen.code.managedagent.store.WorkspaceCreationStore;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedWorkspaceRegistry.WorkspaceSummary;
import com.alibaba.qwen.code.managedagent.persistence.WorkspaceCreationStore;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceDiscoveryService;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceDiscoveryService.WorkspacePage;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.api;
import com.alibaba.qwen.code.managedagent.store.WorkspaceFileStore;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.WorkspaceFileStore;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.JsonNode;
import jakarta.validation.Valid;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.artifact;
import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.ClientException;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.artifact;
public interface ManagedArtifactPolicy {
/** A stable configuration fingerprint that changes whenever a policy decision changes. */
@@ -1,16 +1,17 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.artifact;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ArtifactAccess;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ArtifactResponse;
import com.alibaba.qwen.code.managedagent.api.ApiModels.ToolResultResponse;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.api.TenantContext;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.store.ManagedArtifactReader;
import com.alibaba.qwen.code.managedagent.store.ManagedToolResultStore;
import com.alibaba.qwen.code.managedagent.store.ManagedToolResultStore.Artifact;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ArtifactAccess;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ArtifactResponse;
import com.alibaba.qwen.code.managedagent.model.ApiModels.ToolResultResponse;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellPage;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedArtifactReader;
import com.alibaba.qwen.code.managedagent.persistence.ManagedToolResultStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedToolResultStore.Artifact;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletResponse;
@@ -183,7 +184,7 @@ public class ManagedArtifactService {
throw notFound();
}
if (!policy.readOriginal(tenant.tenantId(), tenant.actorId(), source.workspaceId(), source.sessionId())) {
throw new ApiException(HttpStatus.FORBIDDEN, "artifact_content_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "artifact_content_forbidden",
"The current actor cannot read original artifact bytes.");
}
}
@@ -207,7 +208,7 @@ public class ManagedArtifactService {
}
String etag = "\"" + descriptor.path("sha256").asText() + "\"";
if (ifMatch != null && !matches(ifMatch, etag)) {
throw new ApiException(HttpStatus.PRECONDITION_FAILED, "artifact_revision_mismatch",
throw new ManagedAgentException(HttpStatus.PRECONDITION_FAILED, "artifact_revision_mismatch",
"The artifact validator does not match.");
}
if (ifRange != null && !etag.equals(ifRange.trim())) {
@@ -217,7 +218,7 @@ public class ManagedArtifactService {
Selection selection;
try {
selection = select(range, size);
} catch (ApiException error) {
} catch (ManagedAgentException error) {
if (error.getStatus() == HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE) {
response.setHeader("Content-Range", "bytes */" + size);
}
@@ -225,7 +226,7 @@ public class ManagedArtifactService {
}
if (!readers.tryAcquire()) {
response.setHeader("Retry-After", "1");
throw new ApiException(HttpStatus.TOO_MANY_REQUESTS, "artifact_read_limit",
throw new ManagedAgentException(HttpStatus.TOO_MANY_REQUESTS, "artifact_read_limit",
"The artifact reader limit has been reached.");
}
acquired = true;
@@ -278,7 +279,7 @@ public class ManagedArtifactService {
if (response.isCommitted()) {
throw new IOException("Artifact stream interrupted", error);
}
if (error instanceof ApiException api) {
if (error instanceof ManagedAgentException api) {
if ("tool_output_session_retired".equals(api.getCode())
|| "tool_output_read_expired".equals(api.getCode())) {
session(tenant, sessionId);
@@ -345,7 +346,7 @@ public class ManagedArtifactService {
long start = parsed.getRangeStart(size);
long end = parsed.getRangeEnd(size);
if (size == 0 || start >= size || end < start) {
throw new ApiException(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE, "range_not_satisfiable",
throw new ManagedAgentException(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE, "range_not_satisfiable",
"The range does not intersect this representation.");
}
long length = end - start + 1;
@@ -364,15 +365,15 @@ public class ManagedArtifactService {
return false;
}
private static ApiException badRequest(String code, String message) {
return new ApiException(HttpStatus.BAD_REQUEST, code, message);
private static ManagedAgentException badRequest(String code, String message) {
return new ManagedAgentException(HttpStatus.BAD_REQUEST, code, message);
}
private static ApiException notFound() {
return new ApiException(HttpStatus.NOT_FOUND, "artifact_not_found", "The resource was not found.");
private static ManagedAgentException notFound() {
return new ManagedAgentException(HttpStatus.NOT_FOUND, "artifact_not_found", "The resource was not found.");
}
private static ApiException unavailable() {
return new ApiException(HttpStatus.SERVICE_UNAVAILABLE, "artifact_unavailable", "Artifact content is unavailable.");
private static ManagedAgentException unavailable() {
return new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE, "artifact_unavailable", "Artifact content is unavailable.");
}
}
@@ -1,10 +1,11 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.artifact;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellToolDetails;
import com.alibaba.qwen.code.managedagent.api.TenantContext;
import com.alibaba.qwen.code.managedagent.store.ManagedToolDetailsStore;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellToolDetails;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.model.TenantContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedToolDetailsStore;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@@ -31,7 +32,7 @@ public class ManagedToolDetailsService {
tenant.requireActorId();
SessionRecord session = sessions.requireReadableSession(tenant.tenantId(), tenant.actorId(), sessionId);
if (session.workspace() == null || "DELETING".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "tool_details_not_found", "Tool details are unavailable.");
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "tool_details_not_found", "Tool details are unavailable.");
}
return session;
}
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.artifact;
import java.io.InputStream;
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.artifact;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationRetentionStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.artifact;
import java.util.Objects;
@@ -1,12 +1,12 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.automation;
import com.alibaba.qwen.code.daemon.DaemonHttpException;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrenceRow;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrenceView;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.ScheduleRow;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrenceRow;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrenceView;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.ScheduleRow;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.automation;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -1,26 +1,28 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.automation;
import com.alibaba.qwen.code.daemon.DaemonException;
import com.alibaba.qwen.code.daemon.DaemonHttpException;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AutomationDefinitionRequest;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicAutomation;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicAutomationRun;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.CommandRow;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrenceCursor;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrencePage;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrenceRow;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.OccurrenceView;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.ScheduleCursor;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.SchedulePage;
import com.alibaba.qwen.code.managedagent.store.AutomationLedgerStore.ScheduleRow;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentStore;
import com.alibaba.qwen.code.managedagent.store.ManagedWorkspaceRegistry;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AutomationDefinitionRequest;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicAutomation;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicAutomationRun;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.model.RequestDigests;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.CommandRow;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrenceCursor;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrencePage;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrenceRow;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.OccurrenceView;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.ScheduleCursor;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.SchedulePage;
import com.alibaba.qwen.code.managedagent.persistence.AutomationLedgerStore.ScheduleRow;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedWorkspaceRegistry;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -112,7 +114,7 @@ public class ManagedAutomationService {
requireActor(actorId);
ManagedAgentService.validateIdempotencyKey(idempotencyKey);
if (request.sessionId() == null || request.sessionId().isEmpty()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation", "session_id is required.");
}
Map<String, Object> definition = definition(request, true);
@@ -140,13 +142,13 @@ public class ManagedAutomationService {
if (landed.isEmpty()
&& ledger.countLive(tenantId, session.sessionId())
>= MAX_DEFINITIONS) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_count_limit", "A Session holds at most "
+ MAX_DEFINITIONS + " live automation definitions.");
}
if (landed.isPresent()
&& !landed.get().sessionId().equals(request.sessionId())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_operation_conflict",
"The Idempotency-Key already landed on another Session.");
}
@@ -197,7 +199,7 @@ public class ManagedAutomationService {
requireLive(row);
if (request.sessionId() != null
&& !request.sessionId().equals(row.sessionId())) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation",
"session_id cannot change after creation.");
}
@@ -241,7 +243,7 @@ public class ManagedAutomationService {
try {
session = requireCreatorSession(tenantId, actorId,
row.sessionId());
} catch (ApiException error) {
} catch (ManagedAgentException error) {
// Design decision 9: the Harness commits the terminal
// revision while its Session is reachable. A definition
// whose Session is not ACTIVE (closed, archived) can never
@@ -332,7 +334,7 @@ public class ManagedAutomationService {
occurrenceKey, null, AutomationScanner.TRIGGER_MANUAL,
AutomationLedgerStore.OUTCOME_SKIPPED, refusal,
fence, now), owner);
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_run_skipped",
"The manual run was skipped: " + refusal + ".");
}
@@ -342,7 +344,7 @@ public class ManagedAutomationService {
occurrenceKey, null, AutomationScanner.TRIGGER_MANUAL,
AutomationLedgerStore.OUTCOME_FIRING, null, fence,
now), owner))
.orElseThrow(() -> new ApiException(HttpStatus.CONFLICT,
.orElseThrow(() -> new ManagedAgentException(HttpStatus.CONFLICT,
"automation_busy",
"The automation is being scanned; retry."));
if (AutomationLedgerStore.OUTCOME_FIRING.equals(
@@ -363,7 +365,7 @@ public class ManagedAutomationService {
String reason = ledger.findOccurrence(tenantId,
automationId, occurrenceKey).orElse(occurrence)
.reason();
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_run_skipped",
"The manual run was skipped: " + reason + ".");
}
@@ -470,7 +472,7 @@ public class ManagedAutomationService {
SessionRecord session, Map<String, Object> body) {
try {
return relay(session.tenantId(), session.sessionId(), body);
} catch (ApiException refusal) {
} catch (ManagedAgentException refusal) {
if (PRE_COMMIT_REFUSALS.contains(refusal.getCode())) {
ledger.releaseCommand(tenantId, idempotencyKey, requestDigest,
actorId);
@@ -499,12 +501,12 @@ public class ManagedAutomationService {
return translate(refusal);
}
if (error instanceof UnsupportedOperationException) {
return new ApiException(HttpStatus.SERVICE_UNAVAILABLE,
return new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE,
"automation_unavailable",
"The Hosted Harness is not available.");
}
if (error instanceof DaemonException) {
return new ApiException(HttpStatus.SERVICE_UNAVAILABLE,
return new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE,
"automation_operation_unknown",
"The Hosted Harness answer was lost; retry the same key.");
}
@@ -530,7 +532,7 @@ public class ManagedAutomationService {
break;
}
}
throw new ApiException(HttpStatus.CONFLICT, "automation_busy",
throw new ManagedAgentException(HttpStatus.CONFLICT, "automation_busy",
"The automation is being scanned; retry.");
}
@@ -539,7 +541,7 @@ public class ManagedAutomationService {
Map<String, Object> answer) {
JsonNode schedule = mapper.valueToTree(answer.get("schedule"));
if (schedule == null || !schedule.isObject()) {
throw new ApiException(HttpStatus.SERVICE_UNAVAILABLE,
throw new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE,
"automation_operation_failed",
"The Hosted Harness answered without the definition.");
}
@@ -548,7 +550,7 @@ public class ManagedAutomationService {
schedule.required("scheduleId").asText()).filter(committed ->
committed.sessionId().equals(session.sessionId())
&& committed.recordRevision() >= recordRevision)
.orElseThrow(() -> new ApiException(HttpStatus.SERVICE_UNAVAILABLE,
.orElseThrow(() -> new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE,
"automation_projection_unavailable",
"The committed automation definition is unavailable."));
if (row.recordRevision() > recordRevision) {
@@ -597,19 +599,19 @@ public class ManagedAutomationService {
if (create) {
for (String field : List.of("goal", "cron", "timezone", "prompt")) {
if (!definition.containsKey(field)) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation", field + " is required.");
}
}
}
if (request.prompt() != null && request.prompt()
.getBytes(StandardCharsets.UTF_8).length > 64 * 1024) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation", "prompt exceeds 64 KiB.");
}
if (request.timezone() != null
&& CronSlots.resolve(request.timezone()).isEmpty()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"automation_timezone_unknown",
"The timezone does not resolve on this deployment.");
}
@@ -620,19 +622,19 @@ public class ManagedAutomationService {
// control plane can never mirror, list, fire or retire.
if (request.cron().getBytes(StandardCharsets.UTF_8).length
> 400) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation", "cron exceeds 400 bytes.");
}
try {
CronSlots.compile(request.cron());
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_automation", "The cron is invalid.");
}
}
if (request.sessionMode() != null
&& !"persistent".equals(request.sessionMode())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_mode_disabled",
"Only the persistent target mode is enabled.");
}
@@ -648,7 +650,7 @@ public class ManagedAutomationService {
private static void requireLive(ScheduleRow row) {
if (!AutomationLedgerStore.STATE_LIVE.equals(row.state())) {
throw new ApiException(HttpStatus.CONFLICT, "automation_retired",
throw new ManagedAgentException(HttpStatus.CONFLICT, "automation_retired",
"The automation is retired.");
}
}
@@ -658,7 +660,7 @@ public class ManagedAutomationService {
// scanner reads and the overlap count joins on live; without it a
// fired run would never be seen to end.
if (!settings.isEnabled() || !sessionStoreEnabled) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"automation_unavailable",
"Automation is not enabled on this deployment.");
}
@@ -666,7 +668,7 @@ public class ManagedAutomationService {
private static void requireActor(String actorId) {
if (actorId == null || actorId.isEmpty()) {
throw new ApiException(HttpStatus.UNAUTHORIZED, "actor_required",
throw new ManagedAgentException(HttpStatus.UNAUTHORIZED, "actor_required",
"A trusted actor is required.");
}
}
@@ -674,14 +676,14 @@ public class ManagedAutomationService {
private static void requireScheduleId(String automationId) {
if (automationId == null || !SCHEDULE_ID.matcher(automationId)
.matches()) {
throw new ApiException(HttpStatus.NOT_FOUND,
throw new ManagedAgentException(HttpStatus.NOT_FOUND,
"automation_not_found", "The automation was not found.");
}
}
private static void requireLimit(int limit) {
if (limit < 1 || limit > 100) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_limit",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_limit",
"Limit must be between 1 and 100.");
}
}
@@ -696,7 +698,7 @@ public class ManagedAutomationService {
String actorId, String sessionId) {
Optional<SessionRecord> found = sessions.findSession(tenantId,
sessionId);
ApiException notFound = new ApiException(HttpStatus.NOT_FOUND,
ManagedAgentException notFound = new ManagedAgentException(HttpStatus.NOT_FOUND,
"session_not_found", "The Session was not found.");
if (found.isEmpty() || "DELETED".equals(found.get().status())
|| found.get().workspace() == null
@@ -708,7 +710,7 @@ public class ManagedAutomationService {
// The owner family's refusal, as lifecycle and cwd answer a
// non-creator (SurfaceRegistry rule class OWNER).
if (!workspaces.createdSession(tenantId, actorId, sessionId)) {
throw new ApiException(HttpStatus.FORBIDDEN,
throw new ManagedAgentException(HttpStatus.FORBIDDEN,
"session_operation_forbidden",
"Only the Session's creator manages its automations.");
}
@@ -716,12 +718,12 @@ public class ManagedAutomationService {
.findReadable(tenantId, actorId,
session.workspace().getWorkspaceId());
if (summary == null || !summary.canCreateSession()) {
throw new ApiException(HttpStatus.FORBIDDEN,
throw new ManagedAgentException(HttpStatus.FORBIDDEN,
"session_operation_forbidden",
"The caller may not create in the Session's Workspace.");
}
if (!"ACTIVE".equals(session.status())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"session_not_active", "The Session is not active.");
}
return session;
@@ -730,11 +732,11 @@ public class ManagedAutomationService {
private ScheduleRow requireReadable(String tenantId, String actorId,
String automationId) {
ScheduleRow row = ledger.findSchedule(tenantId, automationId)
.orElseThrow(() -> new ApiException(HttpStatus.NOT_FOUND,
.orElseThrow(() -> new ManagedAgentException(HttpStatus.NOT_FOUND,
"automation_not_found",
"The automation was not found."));
if (!workspaces.canRead(tenantId, actorId, row.workspaceId())) {
throw new ApiException(HttpStatus.NOT_FOUND,
throw new ManagedAgentException(HttpStatus.NOT_FOUND,
"automation_not_found", "The automation was not found.");
}
return row;
@@ -749,7 +751,7 @@ public class ManagedAutomationService {
}
if (!command.get().requestDigest().equals(requestDigest)
|| !command.get().actorId().equals(actorId)) {
throw new ApiException(HttpStatus.CONFLICT, "idempotency_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "idempotency_conflict",
"The idempotency key was reused with different content.");
}
if (command.get().resultJson().isEmpty()) {
@@ -806,7 +808,7 @@ public class ManagedAutomationService {
.toString();
}
static ApiException translate(DaemonHttpException error) {
static ManagedAgentException translate(DaemonHttpException error) {
String code = AutomationScanner.errorCode(error);
HttpStatus status = switch (error.getStatusCode()) {
case 404 -> HttpStatus.NOT_FOUND;
@@ -814,7 +816,7 @@ public class ManagedAutomationService {
case 400 -> HttpStatus.BAD_REQUEST;
default -> HttpStatus.SERVICE_UNAVAILABLE;
};
return new ApiException(status,
return new ManagedAgentException(status,
code == null ? "automation_operation_failed" : code,
"The Hosted Harness refused the automation operation.");
}
@@ -857,7 +859,7 @@ public class ManagedAutomationService {
Long.parseLong(parts[0]);
return parts;
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_cursor",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_cursor",
message);
}
}
@@ -1,6 +1,8 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.catalog;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
@@ -150,8 +152,8 @@ public final class AgentDefinitionExtensions {
return true;
}
private static ApiException unsupported(String field) {
return new ApiException(HttpStatus.CONFLICT, "agent_definition_unsupported",
private static ManagedAgentException unsupported(String field) {
return new ManagedAgentException(HttpStatus.CONFLICT, "agent_definition_unsupported",
"The agent definition field cannot take effect yet.", Map.of("field", field));
}
}
@@ -1,12 +1,14 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.catalog;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AgentDefinition;
import com.alibaba.qwen.code.managedagent.api.ApiModels.AgentDefinitionRequest;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore.Admission;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore.ConcurrentWriteException;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore.DefinitionRevision;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AgentDefinition;
import com.alibaba.qwen.code.managedagent.model.ApiModels.AgentDefinitionRequest;
import com.alibaba.qwen.code.managedagent.model.RequestDigests;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore.Admission;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore.ConcurrentWriteException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore.DefinitionRevision;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -102,7 +104,7 @@ public class ManagedAgentDefinitionService {
admission = write.get();
} catch (ConcurrentWriteException conflict) {
admission = store.replayCommitted(tenantId, idempotencyKey,
requestDigest).orElseThrow(() -> new ApiException(
requestDigest).orElseThrow(() -> new ManagedAgentException(
HttpStatus.CONFLICT, conflict.code(),
conflict.getMessage()));
}
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.catalog;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionRecordStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionRecordStore;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
@@ -1,6 +1,7 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.catalog;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionRecordStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionRecordStore;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
@@ -1,10 +1,10 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.catalog;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionSkills;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSkill;
import com.alibaba.qwen.code.managedagent.store.AgentDefinitionExtensions;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.store.WorkspaceToolProfiles;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionSkills;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSkill;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import org.springframework.stereotype.Service;
import java.util.List;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.api;
package com.alibaba.qwen.code.managedagent.channel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.JsonNode;
@@ -1,42 +1,43 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.channel;
import com.alibaba.qwen.code.daemon.DaemonException;
import com.alibaba.qwen.code.daemon.DaemonHttpException;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicChannel;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicChannelDelivery;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicChannelRoute;
import com.alibaba.qwen.code.managedagent.api.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ChannelInstanceView;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ClaimResponse;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ClaimedDelivery;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ClaimedSegment;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.DeliveryView;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.InboundAdmission;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.InboundEventRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ReceiptRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.RegisterChannelRequest;
import com.alibaba.qwen.code.managedagent.api.ChannelAdapterModels.ResendResponse;
import com.alibaba.qwen.code.managedagent.api.WorkspaceSelection;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ChannelInstanceView;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ClaimResponse;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ClaimedDelivery;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ClaimedSegment;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.DeliveryView;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.InboundAdmission;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.InboundEventRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ReceiptRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.RegisterChannelRequest;
import com.alibaba.qwen.code.managedagent.channel.ChannelAdapterModels.ResendResponse;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.store.ChannelDeliveryRepository;
import com.alibaba.qwen.code.managedagent.store.ChannelDeliveryRepository.ChannelDelivery;
import com.alibaba.qwen.code.managedagent.store.ChannelDeliveryRepository.DeliveryCursor;
import com.alibaba.qwen.code.managedagent.store.ChannelDeliveryRepository.DeliveryPage;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.ChannelBinding;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.ChannelClaim;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.ChannelInstance;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.InstanceCursor;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.InstancePage;
import com.alibaba.qwen.code.managedagent.store.ChannelInstanceStore.PendingDelivery;
import com.alibaba.qwen.code.managedagent.store.ChannelRouteRepository;
import com.alibaba.qwen.code.managedagent.store.ChannelRouteRepository.ChannelRoute;
import com.alibaba.qwen.code.managedagent.store.JdbcChannelDeliveryRepository;
import com.alibaba.qwen.code.managedagent.store.JdbcChannelRouteRepository;
import com.alibaba.qwen.code.managedagent.store.ManagedWorkspaceRegistry;
import com.alibaba.qwen.code.managedagent.model.ApiModels.CommandAdmission;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicChannel;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicChannelDelivery;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicChannelRoute;
import com.alibaba.qwen.code.managedagent.model.ApiModels.PublicList;
import com.alibaba.qwen.code.managedagent.persistence.ChannelDeliveryRepository;
import com.alibaba.qwen.code.managedagent.persistence.ChannelDeliveryRepository.ChannelDelivery;
import com.alibaba.qwen.code.managedagent.persistence.ChannelDeliveryRepository.DeliveryCursor;
import com.alibaba.qwen.code.managedagent.persistence.ChannelDeliveryRepository.DeliveryPage;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.ChannelBinding;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.ChannelClaim;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.ChannelInstance;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.InstanceCursor;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.InstancePage;
import com.alibaba.qwen.code.managedagent.persistence.ChannelInstanceStore.PendingDelivery;
import com.alibaba.qwen.code.managedagent.persistence.ChannelRouteRepository;
import com.alibaba.qwen.code.managedagent.persistence.ChannelRouteRepository.ChannelRoute;
import com.alibaba.qwen.code.managedagent.persistence.JdbcChannelDeliveryRepository;
import com.alibaba.qwen.code.managedagent.persistence.JdbcChannelRouteRepository;
import com.alibaba.qwen.code.managedagent.persistence.ManagedWorkspaceRegistry;
import com.alibaba.qwen.code.managedagent.session.ManagedAgentService;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceSelection;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.codec.digest.DigestUtils;
@@ -133,7 +134,7 @@ public class ManagedChannelService {
try {
policyJson = mapper.writeValueAsString(request.policy());
} catch (com.fasterxml.jackson.core.JsonProcessingException error) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_request",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_request",
"The channel policy is not serializable.");
}
String cwd = request.cwdRelative() == null
@@ -143,7 +144,7 @@ public class ManagedChannelService {
try {
new WorkspaceSelection(request.workspaceId(), cwd);
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_request",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_request",
"The Workspace selection is invalid.");
}
ChannelInstance stored;
@@ -154,7 +155,7 @@ public class ManagedChannelService {
request.actorId(), request.workspaceId(), cwd,
policyJson, 0, 0));
} catch (IllegalStateException error) {
throw new ApiException(HttpStatus.CONFLICT, error.getMessage(),
throw new ManagedAgentException(HttpStatus.CONFLICT, error.getMessage(),
"The channel registration conflicts with the stored"
+ " connection.");
}
@@ -172,12 +173,12 @@ public class ManagedChannelService {
InboundEventRequest event) {
ChannelInstance instance = requireInstance(tenantId, channelId);
if (!"connected".equals(instance.state())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"channel_disconnected",
"The channel is not connected.");
}
if (event.accountGeneration() != instance.accountGeneration()) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
event.accountGeneration() < instance.accountGeneration()
? "channel_generation_stale"
: "channel_generation_unregistered",
@@ -229,7 +230,7 @@ public class ManagedChannelService {
throw translate(error);
}
if (routes.admit(tenantId, routeKey, inputId) == null) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"channel_route_conflict",
"The ingress row was admitted with another input.");
}
@@ -240,7 +241,7 @@ public class ManagedChannelService {
int limit) {
ChannelInstance instance = requireInstance(tenantId, channelId);
if (!"connected".equals(instance.state())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"channel_disconnected",
"The channel is not connected.");
}
@@ -279,7 +280,7 @@ public class ManagedChannelService {
if (request.ordinal() == null
|| request.providerMessageId() == null
|| request.providerMessageId().isBlank()) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_request",
"An accepted receipt names its segment ordinal and"
+ " provider message id.");
@@ -498,7 +499,7 @@ public class ManagedChannelService {
requireReadableInstance(tenantId, actorId, channelId);
return deliveries.find(tenantId, channelId, deliveryId)
.map(ManagedChannelService::publicDelivery)
.orElseThrow(() -> new ApiException(HttpStatus.NOT_FOUND,
.orElseThrow(() -> new ManagedAgentException(HttpStatus.NOT_FOUND,
"delivery_not_found", "The delivery was not found."));
}
@@ -597,7 +598,7 @@ public class ManagedChannelService {
private ChannelDelivery stepLedger(String tenantId, String channelId,
String deliveryId, String state, String providerReceipt, Long claimGeneration) {
ChannelDelivery current = deliveries.find(tenantId, channelId,
deliveryId).orElseThrow(() -> new ApiException(
deliveryId).orElseThrow(() -> new ManagedAgentException(
HttpStatus.NOT_FOUND, "delivery_not_found",
"The delivery was not found."));
if (state.equals(current.state())) {
@@ -696,7 +697,7 @@ public class ManagedChannelService {
try {
bytes = Base64.getDecoder().decode(attachment.bytesBase64());
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"invalid_request",
"An attachment is not base64.");
}
@@ -709,7 +710,7 @@ public class ManagedChannelService {
String channelId) {
requireChannelId(channelId);
return instances.findInstance(tenantId, channelId).orElseThrow(() ->
new ApiException(HttpStatus.NOT_FOUND, "channel_not_found",
new ManagedAgentException(HttpStatus.NOT_FOUND, "channel_not_found",
"The channel was not found."));
}
@@ -717,7 +718,7 @@ public class ManagedChannelService {
String actorId, String channelId) {
ChannelInstance instance = requireInstance(tenantId, channelId);
if (!workspaces.canRead(tenantId, actorId, instance.workspaceId())) {
throw new ApiException(HttpStatus.NOT_FOUND, "channel_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "channel_not_found",
"The channel was not found.");
}
return instance;
@@ -726,37 +727,37 @@ public class ManagedChannelService {
private ChannelClaim requireClaim(String tenantId, String channelId,
String deliveryId) {
return instances.findClaim(tenantId, channelId, deliveryId)
.orElseThrow(() -> new ApiException(HttpStatus.NOT_FOUND,
.orElseThrow(() -> new ManagedAgentException(HttpStatus.NOT_FOUND,
"delivery_not_found", "The delivery was not found."));
}
private static void requireChannelId(String channelId) {
if (channelId == null
|| !channelId.matches("[A-Za-z0-9._:@+-]{1,128}")) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_request",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_request",
"The channel id is invalid.");
}
}
private static void requireLimit(int limit) {
if (limit < 1 || limit > 100) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_limit",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_limit",
"Limit must be between 1 and 100.");
}
}
private static void forbidSeparator(String value, String name) {
if (value.contains(SEPARATOR)) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_request",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_request",
name + " must not contain NUL.");
}
}
private static ApiException translate(DaemonException error) {
private static ManagedAgentException translate(DaemonException error) {
if (!(error instanceof DaemonHttpException http)) {
// A generation clash or dropped connection is transient for the
// adapter: the same retryable envelope an HTTP refusal takes.
return new ApiException(HttpStatus.SERVICE_UNAVAILABLE,
return new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE,
"channel_operation_failed",
"The Hosted Harness failed the channel operation.");
}
@@ -783,7 +784,7 @@ public class ManagedChannelService {
? HttpStatus.SERVICE_UNAVAILABLE : HttpStatus.CONFLICT)
: http.getStatusCode() == 400 ? HttpStatus.BAD_REQUEST
: HttpStatus.SERVICE_UNAVAILABLE;
return new ApiException(status, code,
return new ManagedAgentException(status, code,
"The Hosted Harness refused the channel operation.");
}
@@ -844,7 +845,7 @@ public class ManagedChannelService {
return new String[] {decoded.substring(0, separator),
decoded.substring(separator + 1)};
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.BAD_REQUEST, "invalid_cursor",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "invalid_cursor",
message);
}
}
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.store.AliyunToolPublicationObjectStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationObjectStore;
import com.alibaba.qwen.code.managedagent.artifact.AliyunToolPublicationObjectStore;
import com.alibaba.qwen.code.managedagent.artifact.ToolPublicationObjectStore;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
@@ -1,13 +1,13 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.event.EventTransportConsumer;
import com.alibaba.qwen.code.managedagent.event.LiteTopicEventTransport;
import com.alibaba.qwen.code.managedagent.event.LiteTopicPublicEventTransport;
import com.alibaba.qwen.code.managedagent.event.MessageMaterializer;
import com.alibaba.qwen.code.managedagent.event.TransportWakeActivator;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.service.EventTransportConsumer;
import com.alibaba.qwen.code.managedagent.service.LiteTopicEventTransport;
import com.alibaba.qwen.code.managedagent.service.LiteTopicPublicEventTransport;
import com.alibaba.qwen.code.managedagent.service.MessageMaterializer;
import com.alibaba.qwen.code.managedagent.service.OwnerSubscriptions;
import com.alibaba.qwen.code.managedagent.service.TransportWakeActivator;
import com.alibaba.qwen.code.managedagent.store.TransportConsumerStore;
import com.alibaba.qwen.code.managedagent.persistence.TransportConsumerStore;
import com.alibaba.qwen.code.managedagent.session.OwnerSubscriptions;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientException;
@@ -3,12 +3,12 @@ package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.harness.QwenHostedHarnessConnector;
import com.alibaba.qwen.code.managedagent.harness.UnavailableHarnessConnector;
import com.alibaba.qwen.code.managedagent.store.AgentStateStore;
import com.alibaba.qwen.code.managedagent.store.ManagedActionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.store.SshWorkspaceStore;
import com.alibaba.qwen.code.managedagent.store.WorkspaceExecutionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedActionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.persistence.SshWorkspaceStore;
import com.alibaba.qwen.code.managedagent.persistence.WorkspaceExecutionStore;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.api.ApiExceptionHandler;
import com.alibaba.qwen.code.managedagent.api.PublicSurface;
import com.alibaba.qwen.code.managedagent.security.PublicSurface;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.service.JavaDurableAdmission;
import com.alibaba.qwen.code.managedagent.store.AgentStateStore;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.managedagent.session.JavaDurableAdmission;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.runtimebroker.LocalProcessRuntimeProvisioner;
import com.alibaba.qwen.code.runtimebroker.WorkspaceExecutionProfile;
import com.alibaba.qwen.code.runtimebroker.provisioning.LocalProcessRuntimeProvisioner;
import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -190,7 +190,7 @@ public class ManagedAgentProperties implements EnvironmentAware {
&& !runtimeBroker.getResidentKubernetesApiUrl().isBlank()
&& !runtimeBroker.getResidentKubernetesTokenFile().isBlank() && !runtimeBroker.getResidentKubernetesCaFile().isBlank();
if (!runtimeBroker.getResidentWorkspaces().isEmpty()) {
new com.alibaba.qwen.code.managedagent.store.ResidentWorkspaces(runtimeBroker.getResidentWorkspaces());
new com.alibaba.qwen.code.managedagent.persistence.ResidentWorkspaces(runtimeBroker.getResidentWorkspaces());
if (!residentFiles || !harness.isWorkspaceFilesEnabled()) {
throw new IllegalStateException("Resident Workspaces require exclusive CSI/files configuration");
}
@@ -1181,10 +1181,10 @@ public class ManagedAgentProperties implements EnvironmentAware {
}
public record ResidentWorkspace(String workspaceId, long workspaceGeneration,
com.alibaba.qwen.code.managedagent.store.WorkspaceCsiRegistration registration,
com.alibaba.qwen.code.managedagent.service.WorkspaceCsiResourceGuard.ProtectionIdentity protection,
com.alibaba.qwen.code.managedagent.persistence.WorkspaceCsiRegistration registration,
com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiResourceGuard.ProtectionIdentity protection,
String image, List<String> command,
List<com.alibaba.qwen.code.managedagent.service.WorkspaceCsiRuntimeProvisioner.WorkerArtifact> artifacts) {
List<com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiRuntimeProvisioner.WorkerArtifact> artifacts) {
public ResidentWorkspace {
if (registration == null || protection == null || workspaceId == null || workspaceId.isBlank()
|| workspaceGeneration < 1 || image == null || !image.matches("[^\\s]+@sha256:[0-9a-f]{64}")
@@ -1193,7 +1193,7 @@ public class ManagedAgentProperties implements EnvironmentAware {
|| value.length() > 8192 || value.indexOf('\0') >= 0)
|| artifacts == null || artifacts.size() > 48
|| artifacts.stream().anyMatch(java.util.Objects::isNull)
|| artifacts.stream().map(com.alibaba.qwen.code.managedagent.service.WorkspaceCsiRuntimeProvisioner.WorkerArtifact::configMapName)
|| artifacts.stream().map(com.alibaba.qwen.code.managedagent.workspace.runtime.WorkspaceCsiRuntimeProvisioner.WorkerArtifact::configMapName)
.distinct().count() != artifacts.size()) {
throw new IllegalArgumentException("Invalid resident Workspace configuration");
}
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.service.ManagedArtifactPolicy;
import com.alibaba.qwen.code.managedagent.service.MessageMaterializer;
import com.alibaba.qwen.code.managedagent.artifact.ManagedArtifactPolicy;
import com.alibaba.qwen.code.managedagent.event.MessageMaterializer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.store.ManagedSchemaJdbcTemplate;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSchemaJdbcTemplate;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchema;
import org.springframework.boot.autoconfigure.flyway.FlywayMigrationStrategy;
import org.springframework.context.annotation.Bean;
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.CommitTransactionRequest;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.CommitTransactionRequest;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
@@ -1,19 +1,19 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.service.EmbeddedRuntimeBroker;
import com.alibaba.qwen.code.managedagent.service.RuntimeWarmer;
import com.alibaba.qwen.code.managedagent.store.AgentStateStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationStore;
import com.alibaba.qwen.code.managedagent.store.WorkspaceExecutionStore;
import com.alibaba.qwen.code.runtimebroker.AesGcmSecretProtector;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationStore;
import com.alibaba.qwen.code.managedagent.persistence.WorkspaceExecutionStore;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.managedagent.workspace.runtime.EmbeddedRuntimeBroker;
import com.alibaba.qwen.code.managedagent.workspace.runtime.RuntimeWarmer;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeSessionRepository;
import com.alibaba.qwen.code.runtimebroker.JdbcToolExecutionRepository;
import com.alibaba.qwen.code.runtimebroker.RuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.RuntimeSessionRepository;
import com.alibaba.qwen.code.runtimebroker.SecretProtector;
import com.alibaba.qwen.code.runtimebroker.ToolExecutionRepository;
import com.alibaba.qwen.code.runtimebroker.security.AesGcmSecretProtector;
import com.alibaba.qwen.code.runtimebroker.security.SecretProtector;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -80,7 +80,7 @@ public class RuntimeBrokerConfiguration {
org.springframework.beans.factory.ObjectProvider<ToolPublicationDataStore> publicationData,
org.springframework.jdbc.core.JdbcTemplate jdbc,
org.springframework.transaction.PlatformTransactionManager manager,
com.alibaba.qwen.code.managedagent.service.SshWorkspaceService ssh) {
com.alibaba.qwen.code.managedagent.workspace.SshWorkspaceService ssh) {
return new EmbeddedRuntimeBroker(store, properties,
bindingRepository, sessionRepository, executionRepository,
workspaceExecutionStore, publications.getIfAvailable(),
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.service.RuntimeRetentionJob;
import com.alibaba.qwen.code.managedagent.store.ManagedRuntimeRetentionGuard;
import com.alibaba.qwen.code.managedagent.persistence.ManagedRuntimeRetentionGuard;
import com.alibaba.qwen.code.managedagent.workspace.runtime.RuntimeRetentionJob;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeRetention;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeSessionRepository;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.runtimebroker.SshRuntimeNode;
import com.alibaba.qwen.code.runtimebroker.provisioning.SshRuntimeNode;
import java.util.List;
@@ -1,16 +1,16 @@
package com.alibaba.qwen.code.managedagent.config;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.store.SessionResourceCollectionCollector;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationAdmissionStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationCollector;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationContract;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationObjectStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationRetentionObserver;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationRetentionStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationStore;
import com.alibaba.qwen.code.managedagent.store.ToolPublicationVerifier;
import com.alibaba.qwen.code.managedagent.artifact.ToolPublicationObjectStore;
import com.alibaba.qwen.code.managedagent.artifact.ToolPublicationRetentionObserver;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.persistence.SessionResourceCollectionCollector;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationAdmissionStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationCollector;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationContract;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationDataStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationRetentionStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationStore;
import com.alibaba.qwen.code.managedagent.persistence.ToolPublicationVerifier;
import com.alibaba.qwen.code.runtimebroker.RuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.ToolExecutionRepository;
import org.apache.commons.lang3.StringUtils;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import java.util.List;
@@ -1,8 +1,7 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.CommittedEventPublisher;
import com.alibaba.qwen.code.managedagent.store.EventTransport;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.session.SessionEventHub;
import jdk.jfr.Enabled;
import jdk.jfr.Event;
import jdk.jfr.EventType;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import java.util.List;
@@ -1,8 +1,6 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelope;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelopes;
import com.alibaba.qwen.code.managedagent.store.TransportConsumerStore;
import com.alibaba.qwen.code.managedagent.persistence.TransportConsumerStore;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.message.MessageView;
@@ -1,8 +1,8 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.event;
/**
* The authoritative-journal wire (design 2026-10-04-managed-agent-event-transport,
* phase MQ2b). An after-commit publication point on {@link ManagedSessionStore#commit}
* phase MQ2b). An after-commit publication point on {@link com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStore#commit}
* hands the committed journal record (the raw record bytes) to this port. It is
* distinct from the {@link EventTransport} hub seam, which carries the public
* event stream that MQ2c wires as the {@code public_event} envelope extension.
@@ -1,8 +1,5 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.JournalEventTransport;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelope;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelopes;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
@@ -1,9 +1,6 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.EventTransport;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelope;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelopes;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.message.Message;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.event;
/**
* The managed-event-envelope/1 contract mirrored to Java: the distribution
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.store.AgentStateStore;
import com.alibaba.qwen.code.managedagent.store.StoreModels.MaterializationTarget;
import com.alibaba.qwen.code.managedagent.model.StoreModels.MaterializationTarget;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@@ -1,10 +1,8 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.event;
import com.alibaba.qwen.code.managedagent.harness.HarnessConnector;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelope;
import com.alibaba.qwen.code.managedagent.store.ManagedEventEnvelopes;
import com.alibaba.qwen.code.managedagent.store.TransportConsumerStore;
import com.alibaba.qwen.code.managedagent.store.TransportConsumerStore.WakeFence;
import com.alibaba.qwen.code.managedagent.persistence.TransportConsumerStore;
import com.alibaba.qwen.code.managedagent.persistence.TransportConsumerStore.WakeFence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1,19 +1,19 @@
package com.alibaba.qwen.code.managedagent.api;
package com.alibaba.qwen.code.managedagent.exception;
import org.springframework.http.HttpStatus;
import java.util.Map;
public class ApiException extends RuntimeException {
public class ManagedAgentException extends RuntimeException {
private final HttpStatus status;
private final String code;
private final Map<String, Object> details;
public ApiException(HttpStatus status, String code, String message) {
public ManagedAgentException(HttpStatus status, String code, String message) {
this(status, code, message, Map.of());
}
public ApiException(HttpStatus status, String code, String message,
public ManagedAgentException(HttpStatus status, String code, String message,
Throwable cause) {
this(status, code, message, Map.of(), cause);
}
@@ -22,12 +22,12 @@ public class ApiException extends RuntimeException {
* Creates an error whose envelope carries {@code details} next to its code,
* message and request id.
*/
public ApiException(HttpStatus status, String code, String message,
public ManagedAgentException(HttpStatus status, String code, String message,
Map<String, Object> details) {
this(status, code, message, details, null);
}
private ApiException(HttpStatus status, String code, String message,
private ManagedAgentException(HttpStatus status, String code, String message,
Map<String, Object> details, Throwable cause) {
super(message, cause);
this.status = status;
@@ -31,24 +31,24 @@ public interface HarnessConnector extends AutoCloseable {
default boolean supportsLifecycle() { return false; }
default boolean supportsLifecycle(String profile) {
return com.alibaba.qwen.code.managedagent.store.WorkspaceToolProfiles.FILES.equals(profile) && supportsLifecycle();
return com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles.FILES.equals(profile) && supportsLifecycle();
}
default void prepareLifecycleResources(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
default void prepareLifecycleResources(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
throw new UnsupportedOperationException("Hosted resource lifecycle is unavailable");
}
default void settleLifecycleResources(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
default void settleLifecycleResources(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
throw new UnsupportedOperationException("Hosted resource lifecycle is unavailable");
}
default boolean supportsFencedTitles() { return false; }
default JsonNode settleLifecycle(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
default JsonNode settleLifecycle(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
throw new UnsupportedOperationException("Hosted lifecycle is unavailable");
}
default void detachLifecycle(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
default void detachLifecycle(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
throw new UnsupportedOperationException("Hosted lifecycle is unavailable");
}
@@ -15,18 +15,18 @@ import com.alibaba.qwen.code.daemon.PromptReceipt;
import com.alibaba.qwen.code.daemon.SessionCreationOutcomeUnknownException;
import com.alibaba.qwen.code.daemon.StreamHarnessEvents;
import com.alibaba.qwen.code.daemon.SubmitHarnessTurn;
import com.alibaba.qwen.code.managedagent.catalog.AgentDefinitionExtensions;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.store.AgentDefinitionExtensions;
import com.alibaba.qwen.code.managedagent.store.AgentStateStore;
import com.alibaba.qwen.code.managedagent.store.ManagedActionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.store.SshWorkspaceStore;
import com.alibaba.qwen.code.managedagent.store.StoreModels;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.store.WorkspaceExecutionStore;
import com.alibaba.qwen.code.managedagent.store.WorkspaceToolProfiles;
import com.alibaba.qwen.code.managedagent.store.WriterCredentialPolicy;
import com.alibaba.qwen.code.managedagent.model.StoreModels;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.persistence.ManagedActionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedAgentDefinitionStore;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStore;
import com.alibaba.qwen.code.managedagent.persistence.SshWorkspaceStore;
import com.alibaba.qwen.code.managedagent.persistence.WorkspaceExecutionStore;
import com.alibaba.qwen.code.managedagent.security.WriterCredentialPolicy;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.lang3.StringUtils;
@@ -206,7 +206,7 @@ public class QwenHostedHarnessConnector implements HarnessConnector {
@Override
public com.fasterxml.jackson.databind.JsonNode settleLifecycle(
com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
try {
return doSettleLifecycle(operation, "effects");
} catch (HostedHarnessGenerationException error) {
@@ -216,7 +216,7 @@ public class QwenHostedHarnessConnector implements HarnessConnector {
}
private com.fasterxml.jackson.databind.JsonNode doSettleLifecycle(
com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation, String phase) {
com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation, String phase) {
SessionRecord session = sessions.requireSession(operation.tenantId(), operation.sessionId());
if (operation.lifecycleProtocolVersion() < 0 || operation.lifecycleProtocolVersion() > 2) {
throw new IllegalArgumentException("Unknown lifecycle protocol");
@@ -262,16 +262,16 @@ public class QwenHostedHarnessConnector implements HarnessConnector {
}
@Override
public void prepareLifecycleResources(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
public void prepareLifecycleResources(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
runResourcePhase(operation, "prepare_resources");
}
@Override
public void settleLifecycleResources(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
public void settleLifecycleResources(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
runResourcePhase(operation, "settle_resources");
}
private void runResourcePhase(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation, String phase) {
private void runResourcePhase(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation, String phase) {
try {
doSettleLifecycle(operation, phase);
} catch (HostedHarnessGenerationException error) {
@@ -281,7 +281,7 @@ public class QwenHostedHarnessConnector implements HarnessConnector {
}
@Override
public void detachLifecycle(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
public void detachLifecycle(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
try {
doDetachLifecycle(operation);
} catch (HostedHarnessGenerationException error) {
@@ -290,7 +290,7 @@ public class QwenHostedHarnessConnector implements HarnessConnector {
}
}
private void doDetachLifecycle(com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord operation) {
private void doDetachLifecycle(com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord operation) {
AttachmentKey key = new AttachmentKey(operation.tenantId(), operation.sessionId());
HarnessSessionRef ref = attachments.get(key);
try {
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.api;
package com.alibaba.qwen.code.managedagent.model;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.service;
package com.alibaba.qwen.code.managedagent.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MapperFeature;
@@ -29,7 +29,7 @@ public class RequestDigests {
}
}
int byteLength(Object value) {
public int byteLength(Object value) {
try {
return canonicalMapper.writeValueAsBytes(value).length;
} catch (JsonProcessingException error) {
@@ -1,5 +1,7 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.model;
import com.alibaba.qwen.code.managedagent.persistence.EventIdentity;
import com.alibaba.qwen.code.managedagent.persistence.ManagedWorkspaceRegistry;
import com.alibaba.qwen.code.runtimebroker.managedworkspace.ContextBinding;
import java.util.Arrays;
@@ -1,11 +1,12 @@
package com.alibaba.qwen.code.managedagent.api;
package com.alibaba.qwen.code.managedagent.model;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import org.springframework.http.HttpStatus;
public record TenantContext(String tenantId, String actorId) {
public String requireActorId() {
if (actorId == null) {
throw new ApiException(HttpStatus.UNAUTHORIZED,
throw new ManagedAgentException(HttpStatus.UNAUTHORIZED,
"actor_required", "A trusted actor is required.");
}
return actorId;
@@ -1,6 +1,8 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.catalog.AgentDefinitionExtensions;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
@@ -117,8 +119,8 @@ final class AgentDefinitionCompiler {
return new Compiled(approvalMode, toolProfile);
}
private static ApiException unsupported(String field) {
return new ApiException(HttpStatus.CONFLICT,
private static ManagedAgentException unsupported(String field) {
return new ManagedAgentException(HttpStatus.CONFLICT,
"agent_definition_unsupported",
"The agent definition field cannot take effect yet.",
Map.of("field", field));
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptNamespace;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptScope;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys;
@@ -312,7 +312,7 @@ public class AutomationLedgerStore {
ScheduleRow current = existing.get();
if (!Objects.equals(current.sessionId(), sessionId)
|| !Objects.equals(current.workspaceId(), workspaceId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
ManagedExtensionRecordStore.ERROR_REJECTED,
"A schedule identity belongs to another Session.");
}
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import java.util.List;
import java.util.Optional;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaProjection;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaTime;
@@ -379,7 +379,7 @@ public class ChannelInstanceStore {
if (claims.size() != 1 || !tenantId.equals(claims.getFirst().tenantId())
|| !sessionId.equals(claims.getFirst().sessionId()) || !deliveryId.equals(claims.getFirst().deliveryId())
|| !operationId.equals(reconciliationOperationId(claims.getFirst()))) {
throw new com.alibaba.qwen.code.managedagent.api.ApiException(org.springframework.http.HttpStatus.CONFLICT,
throw new com.alibaba.qwen.code.managedagent.exception.ManagedAgentException(org.springframework.http.HttpStatus.CONFLICT,
"channel_claim_stale", "The channel delivery claim changed before reconciliation committed.");
}
}
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import java.util.List;
import java.util.Optional;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.OperationKind;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.runtimebroker.managedworkspace.ContextBinding;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -146,11 +146,11 @@ public class ChildWorkspaceStore {
}
Row row = find(tenantId, parentSessionId, childRunId);
if (row == null) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_conflict",
"The child Workspace is unavailable.");
}
if (!workspaceMode.equals(row.workspaceMode())) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_conflict",
"The child Workspace was admitted for another mode.");
}
return row;
@@ -312,7 +312,7 @@ public class ChildWorkspaceStore {
List<Row> rows = jdbc.query(SELECT + " WHERE w.tenant_id = ? AND w.parent_session_id = ?"
+ " AND w.child_run_id = ? FOR UPDATE", this::row, tenantId, parentSessionId, childRunId);
if (rows.isEmpty()) {
throw new ApiException(HttpStatus.NOT_FOUND, "child_workspace_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "child_workspace_not_found",
"The child run has no child Workspace.");
}
Row row = rows.getFirst();
@@ -324,16 +324,16 @@ public class ChildWorkspaceStore {
String recorded = asked;
if (MERGE.equals(asked)) {
if (row.finishRequest() != null) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_conflict",
"The child Workspace is already being discarded.");
}
if (!READY.equals(row.state())) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_not_ready",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_not_ready",
"Only a ready child Workspace can be merged.");
}
} else {
if (MERGED.equals(row.state())) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_conflict",
"The child Workspace was already merged.");
}
if (DISCARDED.equals(row.state())) {
@@ -342,7 +342,7 @@ public class ChildWorkspaceStore {
// A merge not yet started (the row is still ready) yields to
// the discard; one that started runs to its end.
if (MERGING.equals(row.state()) || APPLYING.equals(row.state()) || APPLIED.equals(row.state())) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_finishing",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_finishing",
"The child Workspace is being merged.");
}
if (MERGE.equals(row.finishRequest()) && row.resultCommit() == null) {
@@ -1,4 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.model.StoreModels;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.OperationKind;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptNamespace;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.RuntimeBrokerException;
@@ -1,10 +1,12 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationAdmission;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationTarget;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationAdmission;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationTarget;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.OperationKind;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptNamespace;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptScope;
@@ -69,7 +71,7 @@ public class ManagedActionStore {
return actorId == null
? null : ManagedWorkspaceRegistry.actorKey(tenantId, actorId);
} catch (IllegalArgumentException error) {
throw new ApiException(HttpStatus.FORBIDDEN,
throw new ManagedAgentException(HttpStatus.FORBIDDEN,
"actor_scope_mismatch", "Authenticated actor scope is invalid.");
}
}
@@ -107,15 +109,15 @@ public class ManagedActionStore {
private record OwnerRow(byte[] owner, byte[] creator, String workspaceId, String toolProfile) {
}
private static ApiException forbidden() {
return new ApiException(
private static ManagedAgentException forbidden() {
return new ManagedAgentException(
HttpStatus.FORBIDDEN,
"action_forbidden",
"Only the Session's owner or a Workspace operator may answer its Actions.");
}
private static ApiException shellForbidden() {
return new ApiException(
private static ManagedAgentException shellForbidden() {
return new ManagedAgentException(
HttpStatus.FORBIDDEN,
"action_forbidden",
"Only the Session's recorded owner may answer its Shell Actions.");
@@ -461,7 +463,7 @@ public class ManagedActionStore {
OperationRecord existing =
sessions.findOperation(tenantId, sessionId, replay.get(0)).orElseThrow();
if (!existing.requestDigest().equals(requestDigest)) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
@@ -540,7 +542,7 @@ public class ManagedActionStore {
if (ownerRow.workspaceId() != null
&& !sessions.hasExecutionRegistryFacts(tenantId,
sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"workspace_unavailable",
"Hosted Workspace execution is not available.");
}
@@ -621,27 +623,27 @@ public class ManagedActionStore {
// reach — whichever arm admitted the caller.
if (ownerRow.workspaceId() != null
&& !sessions.hasExecutionRegistryFacts(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT, "workspace_unavailable",
throw new ManagedAgentException(HttpStatus.CONFLICT, "workspace_unavailable",
"Hosted Workspace execution is not available.");
}
WorkspaceMigrationAdmission.requireSessionOpen(jdbc, tenantId, sessionId);
String sessionStatus = jdbc.queryForObject("SELECT status FROM ma_session"
+ " WHERE tenant_id = ? AND session_id = ?", String.class, tenantId, sessionId);
if (!"ACTIVE".equals(sessionStatus)) {
throw new ApiException(HttpStatus.CONFLICT, "session_inactive", "The Session does not accept responses.");
throw new ManagedAgentException(HttpStatus.CONFLICT, "session_inactive", "The Session does not accept responses.");
}
Action action =
find(tenantId, sessionId, actionId)
.orElseThrow(
() ->
new ApiException(
new ManagedAgentException(
HttpStatus.NOT_FOUND,
"action_not_found",
"The Action was not found."));
JsonNode o = action.options();
if (publicPlanExit(tenantId, sessionId, o)
&& (!admitted || !workspaceOperatorAdmits(tenantId, ownerRow, actorId))) {
throw new ApiException(HttpStatus.FORBIDDEN, "action_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "action_forbidden",
"Only the Session owner with current OPERATOR access may approve a public plan.");
}
if (body.size() != 3
@@ -650,19 +652,19 @@ public class ManagedActionStore {
|| !body.path("inputRevision").isIntegralNumber()
|| body.path("inputRevision").asLong() != o.path("inputRevision").asLong()
|| !body.path("policyRevision").equals(o.path("policyRevision"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.BAD_REQUEST,
"invalid_action_response",
"The response does not match the original Action.");
}
if (!"requested".equals(action.state())) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
endedCode(action.state()),
"The Action has already ended.");
}
if (now >= o.path("expiresAt").asLong()) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT, "action_expired", "The Action has expired.");
}
String scope = ManagedSessionStore.sessionScopeKey(tenantId, sessionId);
@@ -675,7 +677,7 @@ public class ManagedActionStore {
(r, row) -> new String[]{r.getString(1), r.getString(2)}, ManagedSchemaKeys.key(tenantId), actionScope);
if (!reserved.isEmpty()) {
if (!decision.equals(reserved.getFirst()[0])) {
throw new ApiException(HttpStatus.CONFLICT, "action_already_resolved", "A different Action decision is already admitted.");
throw new ManagedAgentException(HttpStatus.CONFLICT, "action_already_resolved", "A different Action decision is already admitted.");
}
String original = jdbc.queryForObject("SELECT operation_id FROM ma_operation WHERE operation_key = ?",
String.class, reserved.getFirst()[1]);
@@ -849,7 +851,7 @@ public class ManagedActionStore {
private static void require(boolean valid) {
if (!valid) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.BAD_REQUEST,
"managed_session_action_rejected",
"The Action journal record is invalid.");
@@ -1,8 +1,8 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.service.RequestDigests;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.RequestDigests;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptNamespace;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaContract.ReceiptScope;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys;
@@ -124,7 +124,7 @@ public class ManagedAgentDefinitionStore {
if (!revision.digest().equals(session.agentDefinitionDigest())
|| !digests.digest(content)
.equals("sha256:" + session.agentDefinitionDigest())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"hosted_agent_definition_conflict",
"The pinned agent definition digest does not match.");
}
@@ -186,7 +186,7 @@ public class ManagedAgentDefinitionStore {
}
String[] command = commands.getFirst();
if (!command[0].equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The Idempotency-Key was used with a different request.");
}
@@ -239,8 +239,8 @@ public class ManagedAgentDefinitionStore {
return rows.isEmpty() ? Optional.empty() : Optional.of(rows.getFirst());
}
public static ApiException notFound() {
return new ApiException(HttpStatus.NOT_FOUND, "agent_not_found",
public static ManagedAgentException notFound() {
return new ManagedAgentException(HttpStatus.NOT_FOUND, "agent_not_found",
"The agent definition was not found.");
}
}
@@ -1,46 +1,50 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellApprovalChangeResult;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellApprovalSelection;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelChangeResult;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelContext;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelOption;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelSelection;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellSessionOptions;
import com.alibaba.qwen.code.managedagent.api.WorkspaceSelection;
import com.alibaba.qwen.code.managedagent.config.ManagedAgentProperties;
import com.alibaba.qwen.code.managedagent.store.EventIdentity.Identity;
import com.alibaba.qwen.code.managedagent.store.ManagedWorkspaceRegistry.ResolvedBinding;
import com.alibaba.qwen.code.managedagent.store.StoreModels.AcceptanceVerdict;
import com.alibaba.qwen.code.managedagent.store.StoreModels.Admission;
import com.alibaba.qwen.code.managedagent.store.StoreModels.CommandRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.DispatchTarget;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventPage;
import com.alibaba.qwen.code.managedagent.store.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.HarnessEvent;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ItemPartRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ItemRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.MaterializationResult;
import com.alibaba.qwen.code.managedagent.store.StoreModels.MaterializationTarget;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationAdmission;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.OperationTarget;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ParkedOperation;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ProjectedEvent;
import com.alibaba.qwen.code.managedagent.store.StoreModels.RenameDelivery;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ReplayFloorTarget;
import com.alibaba.qwen.code.managedagent.store.StoreModels.ReplayWindow;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionMutation;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionMutationCommand;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionMutationKind;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionPage;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.SnapshotRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.TurnPage;
import com.alibaba.qwen.code.managedagent.store.StoreModels.TurnRecord;
import com.alibaba.qwen.code.managedagent.store.StoreModels.TurnSummary;
import com.alibaba.qwen.code.managedagent.event.CommittedEventPublisher;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellApprovalChangeResult;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellApprovalSelection;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelChangeResult;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelContext;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelOption;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelSelection;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellSessionOptions;
import com.alibaba.qwen.code.managedagent.model.StoreModels;
import com.alibaba.qwen.code.managedagent.model.StoreModels.AcceptanceVerdict;
import com.alibaba.qwen.code.managedagent.model.StoreModels.Admission;
import com.alibaba.qwen.code.managedagent.model.StoreModels.CommandRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.DispatchTarget;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventPage;
import com.alibaba.qwen.code.managedagent.model.StoreModels.EventRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.HarnessEvent;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ItemPartRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ItemRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.MaterializationResult;
import com.alibaba.qwen.code.managedagent.model.StoreModels.MaterializationTarget;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationAdmission;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationKind;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.OperationTarget;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ParkedOperation;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ProjectedEvent;
import com.alibaba.qwen.code.managedagent.model.StoreModels.RenameDelivery;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ReplayFloorTarget;
import com.alibaba.qwen.code.managedagent.model.StoreModels.ReplayWindow;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionMutation;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionMutationCommand;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionMutationKind;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionPage;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SessionRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.SnapshotRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.TurnPage;
import com.alibaba.qwen.code.managedagent.model.StoreModels.TurnRecord;
import com.alibaba.qwen.code.managedagent.model.StoreModels.TurnSummary;
import com.alibaba.qwen.code.managedagent.persistence.EventIdentity.Identity;
import com.alibaba.qwen.code.managedagent.persistence.ManagedWorkspaceRegistry.ResolvedBinding;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceSelection;
import com.alibaba.qwen.code.managedagent.workspace.WorkspaceToolProfiles;
import com.alibaba.qwen.code.runtimebroker.CsiFilesRetirementProfile;
import com.alibaba.qwen.code.runtimebroker.JdbcRuntimeBindingRepository;
import com.alibaba.qwen.code.runtimebroker.RuntimeProvisionRequest;
@@ -404,7 +408,7 @@ public class ManagedAgentStore implements AgentStateStore {
if (planMode && (!planModeSupported || !approvalSelectionSupported
|| pin.hooks() || !(WorkspaceToolProfiles.FILES.equals(pin.toolProfile())
|| WorkspaceToolProfiles.isPublicShell(pin.toolProfile())))) {
throw new ApiException(HttpStatus.CONFLICT, "unsupported_feature", "Plan mode is unavailable");
throw new ManagedAgentException(HttpStatus.CONFLICT, "unsupported_feature", "Plan mode is unavailable");
}
if (!input.isEmpty() && WorkspaceToolProfiles.isPublicShell(pin.toolProfile())
&& !workspaceShellEnabled) {
@@ -492,7 +496,7 @@ public class ManagedAgentStore implements AgentStateStore {
List<WorkspaceCommand> existing = findWorkspaceCommand(tenantId,
actorId, idempotencyKey);
if (existing.isEmpty()) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict", "The creation command is missing.");
}
return replayWorkspaceCommand(tenantId, actorId, requestDigest,
@@ -624,7 +628,7 @@ public class ManagedAgentStore implements AgentStateStore {
parentSessionId);
if (parent.workspace() == null || residentWorkspaces.find(parent.workspace()) != null || !"ACTIVE".equals(parent.status())
|| CsiFilesRetirementProfile.PROFILE.equals(parent.toolProfile())) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"child_parent_unavailable",
"The parent Session cannot admit a child.");
}
@@ -635,7 +639,7 @@ public class ManagedAgentStore implements AgentStateStore {
if (!existing.isEmpty()) {
WorkspaceCommand command = existing.getFirst();
if (!command.requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
@@ -666,7 +670,7 @@ public class ManagedAgentStore implements AgentStateStore {
&& ("completed".equals(runState.getFirst())
|| "failed".equals(runState.getFirst())
|| "cancelled".equals(runState.getFirst()))) {
throw new ApiException(HttpStatus.CONFLICT, "child_run_settled",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_run_settled",
"The child run already settled; creation owes no more Session.");
}
// A child bound to a snapshot reads with the read-only profile
@@ -778,7 +782,7 @@ public class ManagedAgentStore implements AgentStateStore {
childRunId,
tenantId);
if (ready.size() != 1 || !ready.getFirst()) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_not_ready",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_not_ready",
"The child run's Workspace is not ready to bind a child Session.");
}
// The request is written once, when the row is admitted, so the
@@ -790,7 +794,7 @@ public class ManagedAgentStore implements AgentStateStore {
+ " AND w.child_run_id = ? AND w.tenant_id = ?",
String.class, parentSessionId, childRunId, tenantId);
if (requests.size() != 1) {
throw new ApiException(HttpStatus.CONFLICT, "child_workspace_not_ready",
throw new ManagedAgentException(HttpStatus.CONFLICT, "child_workspace_not_ready",
"The child run's Workspace is not ready to bind a child Session.");
}
return ChildWorkspaceStore.workspaceMode(requests.getFirst());
@@ -803,7 +807,7 @@ public class ManagedAgentStore implements AgentStateStore {
String requestDigest) {
SessionRecord parent = requireSessionForUpdate(tenantId, parentSessionId);
if (CsiFilesRetirementProfile.PROFILE.equals(parent.toolProfile())) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"child_parent_unavailable",
"The parent Session cannot admit a child.");
@@ -812,12 +816,12 @@ public class ManagedAgentStore implements AgentStateStore {
List<WorkspaceCommand> existing = findWorkspaceCommand(tenantId,
childActorOf(parentSessionId), idempotencyKey);
if (existing.isEmpty()) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict", "The creation command is missing.");
}
WorkspaceCommand command = existing.getFirst();
if (!command.requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
@@ -855,17 +859,17 @@ public class ManagedAgentStore implements AgentStateStore {
|| internalTeamLead != WorkspaceToolProfiles.INTERNAL_TEAM_LEAD.equals(session.toolProfile())
|| internalTeamLead && (!"qwen-code".equals(session.agentId())
|| session.agentDefinitionDigest() != null)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
ContextBinding bound = session.workspace();
if (bound == null) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"workspace_unavailable", "Workspace binding is missing.");
}
if (!workspaces.canRead(tenantId, actorId, bound.getWorkspaceId())) {
throw new ApiException(HttpStatus.NOT_FOUND,
throw new ManagedAgentException(HttpStatus.NOT_FOUND,
"workspace_not_found", "Workspace not found.");
}
return new Admission(command.sessionId(), command.turnId(), true,
@@ -895,8 +899,8 @@ public class ManagedAgentStore implements AgentStateStore {
return kind == SessionMutationKind.RENAME && workspaceFilesEnabled;
}
private static ApiException workspaceExecutionUnavailable() {
return new ApiException(HttpStatus.CONFLICT,
private static ManagedAgentException workspaceExecutionUnavailable() {
return new ManagedAgentException(HttpStatus.CONFLICT,
"workspace_unavailable",
"Hosted Workspace execution is not available.");
}
@@ -915,7 +919,7 @@ public class ManagedAgentStore implements AgentStateStore {
tenantId, idempotencyKey, true);
if (existing == null
|| !Boolean.valueOf(workspaceBound).equals(existing.workspaceBound())) {
throw new ApiException(HttpStatus.CONFLICT, "idempotency_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "idempotency_conflict",
"The idempotency key was reused with different content.");
}
}
@@ -973,7 +977,7 @@ public class ManagedAgentStore implements AgentStateStore {
if (!availableApprovalModes(pin).contains(requested)
&& !(supported && pin.digest() == null && "yolo".equals(requested)
&& WorkspaceToolProfiles.isPublicShell(pin.toolProfile()))) {
throw new ApiException(HttpStatus.BAD_REQUEST, "unsupported_approval_mode",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "unsupported_approval_mode",
"The selected approval mode is not available for this Agent.");
}
return new AgentPin(pin.revision(), pin.digest(), requested, pin.toolProfile(), pin.hooks());
@@ -985,7 +989,7 @@ public class ManagedAgentStore implements AgentStateStore {
String requested, boolean workspaceBound) {
if ("qwen-code".equals(agentId)) {
if (requested != null && !requested.equals(agentRevision)) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_feature",
"Only the current agent revision can be selected.");
}
@@ -1183,11 +1187,11 @@ public class ManagedAgentStore implements AgentStateStore {
WorkspaceMigrationAdmission.requireOpen(jdbc, tenantId, session.workspace().getStorageId());
}
if (!"ACTIVE".equals(session.status())) {
throw new ApiException(HttpStatus.CONFLICT, "session_not_active",
throw new ManagedAgentException(HttpStatus.CONFLICT, "session_not_active",
"The Session does not accept new Turns.");
}
if (hasActiveTurn(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT, "turn_active",
throw new ManagedAgentException(HttpStatus.CONFLICT, "turn_active",
"The Session already has an active Turn.");
}
// The W2 handshake: an open execution operation on a bound Session
@@ -1200,7 +1204,7 @@ public class ManagedAgentStore implements AgentStateStore {
// intentionally cover them stay untouched.
if (session.workspace() != null
&& hasOpenExecutionOperation(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"session_context_busy",
"The Session has an open operation.");
}
@@ -1305,13 +1309,13 @@ public class ManagedAgentStore implements AgentStateStore {
Map<String, Object> row = retained.getFirst();
if (!key.equals(row.get("idempotency_key")) || !digest.equals(row.get("request_digest"))
|| !title.equals(readMap((String) row.get("request_json")).get("title"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
if ("SUPERSEDED".equals(row.get("state"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"session_mutation_superseded",
"A later Session title attempt has been admitted.");
@@ -1320,7 +1324,7 @@ public class ManagedAgentStore implements AgentStateStore {
// reconciler and is never re-sent.
if ("RECOVERY_BLOCKED".equals(row.get("state"))
|| "UNKNOWN".equals(row.get("state"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"operation_outcome_unknown",
"The original title delivery is awaiting reconciliation.");
@@ -1414,10 +1418,10 @@ public class ManagedAgentStore implements AgentStateStore {
&& !workspaces.createdSession(session.tenantId(), actorId,
session.sessionId())) {
if ("DELETED".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found.");
}
throw new ApiException(HttpStatus.CONFLICT, "workspace_unavailable",
throw new ManagedAgentException(HttpStatus.CONFLICT, "workspace_unavailable",
"Hosted Workspace execution is not available.");
}
}
@@ -1461,7 +1465,7 @@ public class ManagedAgentStore implements AgentStateStore {
.equals(
readMap((String) rows.getFirst().get("request_json"))
.get("title"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"session_mutation_superseded",
"A later Session title attempt has been admitted.");
@@ -1474,7 +1478,7 @@ public class ManagedAgentStore implements AgentStateStore {
!= ((Number) operation.get("claim_generation")).longValue()
|| !List.of("RUNNING", "RECOVERY_BLOCKED", "UNKNOWN")
.contains(operation.get("state"))) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"operation_claim_lost",
"The title delivery claim was lost.");
@@ -1581,7 +1585,7 @@ public class ManagedAgentStore implements AgentStateStore {
owner,
delivery.claimGeneration());
if (changed != 1) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.CONFLICT,
"operation_claim_lost",
"The title delivery claim was lost.");
@@ -1696,7 +1700,7 @@ public class ManagedAgentStore implements AgentStateStore {
CommandRecord command = existing.get();
if (!command.requestDigest().equals(requestDigest)
|| !command.sessionId().equals(sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
@@ -1757,7 +1761,7 @@ public class ManagedAgentStore implements AgentStateStore {
new IllegalStateException(
"Session mutation command is unavailable"));
if (!command.sessionId().equals(sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key belongs to another Session.");
}
@@ -1775,7 +1779,7 @@ public class ManagedAgentStore implements AgentStateStore {
// completing this one now would revert that newer outcome.
if ("FAILED".equals(command.status()) && supersededByLaterMutation(
tenantId, sessionId, operation, idempotencyKey, kind)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"session_mutation_superseded",
"A later change to the Session completed after this"
+ " request was retired.");
@@ -1904,11 +1908,11 @@ public class ManagedAgentStore implements AgentStateStore {
// invisible; a readable non-owner gets the sibling family's 403.
private void requireWorkspaceCreator(SessionRecord session, String actorId) {
if (!workspaces.canRead(session.tenantId(), actorId, session.workspace().getWorkspaceId())) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found.");
}
if (!workspaces.isSessionOwner(session.tenantId(), actorId, session.sessionId())) {
throw new ApiException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
"Only the Session owner may manage it.");
}
}
@@ -1926,7 +1930,7 @@ public class ManagedAgentStore implements AgentStateStore {
Optional<CommandRecord> existing = findCommand(tenantId, namespace, scopedKey, true);
if (existing.isPresent()) {
if (!existing.get().requestDigest().equals(requestDigest) || !existing.get().sessionId().equals(sessionId)) {
throw new ApiException(HttpStatus.CONFLICT, "idempotency_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "idempotency_conflict",
"The idempotency key was reused with different content.");
}
return new SessionMutation(session, true);
@@ -1935,7 +1939,7 @@ public class ManagedAgentStore implements AgentStateStore {
// refusal: a fresh key against a deleted Session must not answer
// a retryable 409 for a Session that will never come back.
if ("DELETED".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found.");
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found.");
}
if (WorkspaceToolProfiles.isShellOrMcp(session.toolProfile())
&& (WorkspaceToolProfiles.lifecycleProtocol(session.toolProfile()) != 2
@@ -2236,7 +2240,7 @@ public class ManagedAgentStore implements AgentStateStore {
|| !(lineage.getFirst().get("creator_actor_key") instanceof byte[] actor)
|| actor.length == 0
|| !java.util.Arrays.equals(actor, creator)) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.NOT_FOUND,
"session_not_found",
"The child Session lineage was not found.");
@@ -2285,14 +2289,14 @@ public class ManagedAgentStore implements AgentStateStore {
kind, actorDigest, idempotencyKey);
if (existing.isPresent()) {
if (!existing.get().requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
return new OperationAdmission(existing.get(), true);
}
if ("DELETED".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found.");
}
// A terminally FAILED operation leaves the Session in the pending
@@ -2330,7 +2334,7 @@ public class ManagedAgentStore implements AgentStateStore {
throw workspaceExecutionUnavailable();
}
if (hasPendingRenameDelivery(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT, "session_operation_active",
throw new ManagedAgentException(HttpStatus.CONFLICT, "session_operation_active",
"The Session has a title delivery awaiting completion.");
}
if (session.workspace() != null) {
@@ -2494,7 +2498,7 @@ public class ManagedAgentStore implements AgentStateStore {
SessionRecord session = requireLegacySessionForUpdate(tenantId, sessionId);
ContextBinding binding = session.workspace();
if (binding == null) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
"unsupported_feature",
"The Session has no Workspace context.");
}
@@ -2510,21 +2514,21 @@ public class ManagedAgentStore implements AgentStateStore {
WorkspaceAccess cwdAccess = workspaces.accessOf(session.tenantId(),
actorId, binding.getWorkspaceId());
if (!cwdAccess.canRead()) {
throw new ApiException(
throw new ManagedAgentException(
HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found.");
}
Optional<OperationRecord> existing = replayOperation(tenantId, sessionId,
OperationKind.CWD_CHANGE, actorDigest, idempotencyKey);
if (existing.isPresent()) {
if (!existing.get().requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
return new OperationAdmission(existing.get(), true);
}
if (!cwdAccess.atLeast(WorkspaceAccess.OPERATOR)) {
throw new ApiException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
"Only a Workspace operator may change the Session directory.");
}
if (residentWorkspaces.find(binding) != null) {
@@ -2536,7 +2540,7 @@ public class ManagedAgentStore implements AgentStateStore {
throw workspaceExecutionUnavailable();
}
if ("DELETED".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found.");
}
if (!"ACTIVE".equals(session.status())) {
@@ -2544,7 +2548,7 @@ public class ManagedAgentStore implements AgentStateStore {
}
requireCwdChangeRegistryFacts(session);
if (binding.getContextRevision() != expectedContextRevision) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"context_revision_conflict",
"The Session context revision has changed.");
}
@@ -2556,7 +2560,7 @@ public class ManagedAgentStore implements AgentStateStore {
|| hasActiveTurn(tenantId, sessionId)
|| hasDecidableAction(session)
|| hasRetainedRuntimeSession(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"session_context_busy",
"The Session has an active Turn, operation or retained Runtime context.");
}
@@ -2763,18 +2767,18 @@ public class ManagedAgentStore implements AgentStateStore {
OperationKind.TASK_CANCEL, actorDigest, idempotencyKey);
if (existing.isPresent()) {
if (!existing.get().requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
return new OperationAdmission(existing.get(), true);
}
if ("DELETED".equals(session.status())) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found.");
}
if (!"ACTIVE".equals(session.status())) {
throw new ApiException(HttpStatus.CONFLICT, "session_not_active",
throw new ManagedAgentException(HttpStatus.CONFLICT, "session_not_active",
"The Session is " + session.status().toLowerCase(
java.util.Locale.ROOT)
+ " and accepts no task cancellation.");
@@ -2791,12 +2795,12 @@ public class ManagedAgentStore implements AgentStateStore {
ManagedSessionStore.sessionScopeKey(tenantId, sessionId),
taskId.substring("task_".length()));
if (task.isEmpty()) {
throw new ApiException(HttpStatus.NOT_FOUND, "task_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "task_not_found",
"The task was not found.");
}
if (!ManagedExtensionProjection.taskActions(task.getFirst()[0],
task.getFirst()[1]).contains("cancel")) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"task_action_unavailable",
"The task does not accept a cancellation now.");
}
@@ -3813,12 +3817,12 @@ public class ManagedAgentStore implements AgentStateStore {
ManagedReceipts.Receipt command = ManagedReceipts.command(jdbc,
tenantId, operation, idempotencyKey, false);
if (command == null) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key is already in use.");
}
if (!command.requestDigest().equals(requestDigest)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"idempotency_conflict",
"The idempotency key was reused with different content.");
}
@@ -4022,7 +4026,7 @@ public class ManagedAgentStore implements AgentStateStore {
? null : new WebShellModelSelection(row.getString("model_id"),
row.getLong("model_revision")), tenantId, sessionId, promptId);
if (rows.size() != 1) {
throw new ApiException(HttpStatus.CONFLICT, "turn_not_found", "The model snapshot Turn was not found");
throw new ManagedAgentException(HttpStatus.CONFLICT, "turn_not_found", "The model snapshot Turn was not found");
}
return rows.getFirst();
}
@@ -4035,12 +4039,12 @@ public class ManagedAgentStore implements AgentStateStore {
WorkspaceMigrationAdmission.lockTenant(jdbc, tenantId);
SessionRecord session = requireLegacySessionForUpdate(tenantId, sessionId);
if (session.workspace() == null) {
throw new ApiException(HttpStatus.BAD_REQUEST, "unsupported_feature",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "unsupported_feature",
"Model selection requires a Workspace Session");
}
WorkspaceAccess access = workspaces.accessOf(tenantId, actorId, session.workspace().getWorkspaceId());
if (!access.canRead()) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found");
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found");
}
String scope = com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys
.key("SET_MODEL", sessionId, actorId);
@@ -4054,7 +4058,7 @@ public class ManagedAgentStore implements AgentStateStore {
|| !"SET_MODEL".equals(replay.operation())
|| !java.util.Arrays.equals(actorId.getBytes(StandardCharsets.UTF_8),
replay.actorKey())) {
throw new ApiException(HttpStatus.CONFLICT, "idempotency_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "idempotency_conflict",
"The idempotency key was reused with different content");
}
Map<String, Object> result = readMap(replay.resultJson());
@@ -4062,20 +4066,20 @@ public class ManagedAgentStore implements AgentStateStore {
(String) result.get("modelId"), ((Number) result.get("revision")).longValue()), true);
}
if (!access.atLeast(WorkspaceAccess.OPERATOR)) {
throw new ApiException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
"Only a Workspace operator may change the model");
}
if (!supported || modelCatalog.isEmpty() || !workspaceFilesEnabled) {
throw new ApiException(HttpStatus.CONFLICT, "unsupported_feature", "Model selection is unavailable");
throw new ManagedAgentException(HttpStatus.CONFLICT, "unsupported_feature", "Model selection is unavailable");
}
if (modelCatalog.stream().noneMatch(option -> option.modelId().equals(modelId))) {
throw new ApiException(HttpStatus.BAD_REQUEST, "unsupported_model", "The model is not published by this host");
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "unsupported_model", "The model is not published by this host");
}
requireIdlePolicyChange(session);
long current = jdbc.queryForObject("SELECT model_revision FROM ma_session WHERE tenant_id = ?"
+ " AND session_id = ?", Long.class, tenantId, sessionId);
if (current != expectedRevision || current >= 9_007_199_254_740_991L) {
throw new ApiException(HttpStatus.CONFLICT, "model_selection_conflict", "The model revision changed");
throw new ManagedAgentException(HttpStatus.CONFLICT, "model_selection_conflict", "The model revision changed");
}
long revision = current + 1;
long now = clock.millis();
@@ -4149,14 +4153,14 @@ public class ManagedAgentStore implements AgentStateStore {
}
String mode = row.getString("approval_mode");
if (mode == null && row.getLong("selected_revision") != 0) {
throw new ApiException(HttpStatus.CONFLICT, "approval_snapshot_missing", "The Turn has no approval snapshot");
throw new ManagedAgentException(HttpStatus.CONFLICT, "approval_snapshot_missing", "The Turn has no approval snapshot");
}
// Legacy prompt replays must preserve the original absence of a selection.
return mode == null ? null : new WebShellApprovalSelection(mode, row.getLong("approval_revision"),
row.getBoolean("plan_enabled"));
}, tenantId, sessionId, promptId);
if (rows.size() != 1) {
throw new ApiException(HttpStatus.CONFLICT, "turn_not_found", "The Turn was not found");
throw new ManagedAgentException(HttpStatus.CONFLICT, "turn_not_found", "The Turn was not found");
}
return rows.getFirst();
}
@@ -4178,16 +4182,16 @@ public class ManagedAgentStore implements AgentStateStore {
WorkspaceMigrationAdmission.lockTenant(jdbc, tenantId);
SessionRecord session = requireLegacySessionForUpdate(tenantId, sessionId);
if (session.workspace() == null) {
throw new ApiException(HttpStatus.BAD_REQUEST, "unsupported_feature",
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "unsupported_feature",
"Approval selection requires a Workspace Session");
}
WorkspaceAccess access = workspaces.accessOf(tenantId, actorId, session.workspace().getWorkspaceId());
if (!access.canRead()) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found");
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found", "The Session was not found");
}
if (!workspaces.isSessionOwner(tenantId, actorId, sessionId)
|| !access.atLeast(WorkspaceAccess.OPERATOR)) {
throw new ApiException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
throw new ManagedAgentException(HttpStatus.FORBIDDEN, "session_operation_forbidden",
"Only the Session owner with OPERATOR access may change approval policy");
}
String scope = com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys
@@ -4202,7 +4206,7 @@ public class ManagedAgentStore implements AgentStateStore {
|| !"SET_APPROVAL".equals(replay.operation())
|| !java.util.Arrays.equals(actorId.getBytes(StandardCharsets.UTF_8),
replay.actorKey())) {
throw new ApiException(HttpStatus.CONFLICT, "idempotency_conflict",
throw new ManagedAgentException(HttpStatus.CONFLICT, "idempotency_conflict",
"The idempotency key was reused with different content");
}
Map<String, Object> result = readMap(replay.resultJson());
@@ -4212,23 +4216,23 @@ public class ManagedAgentStore implements AgentStateStore {
if (!supported || session.agentDefinitionDigest() != null && !agentDefinitionSupported
|| !workspaceFilesEnabled || !WorkspaceToolProfiles.supportsApprovalSelection(session)
|| WorkspaceToolProfiles.isPublicShell(session.toolProfile()) && !workspaceShellEnabled) {
throw new ApiException(HttpStatus.CONFLICT, "unsupported_feature", "Approval selection is unavailable");
throw new ManagedAgentException(HttpStatus.CONFLICT, "unsupported_feature", "Approval selection is unavailable");
}
if (!WorkspaceToolProfiles.supportsApprovalMode(mode)) {
throw new ApiException(HttpStatus.BAD_REQUEST, "unsupported_approval_mode", "The approval mode is unavailable");
throw new ManagedAgentException(HttpStatus.BAD_REQUEST, "unsupported_approval_mode", "The approval mode is unavailable");
}
boolean planMode = requestedPlanMode == null
? Boolean.TRUE.equals(jdbc.queryForObject("SELECT plan_enabled FROM ma_session WHERE tenant_id=? AND session_id=?",
Boolean.class, tenantId, sessionId)) : requestedPlanMode;
if (planMode && (!planModeSupported || !supportsPlanMode(session))) {
throw new ApiException(HttpStatus.CONFLICT, "unsupported_feature", "Plan mode is unavailable");
throw new ManagedAgentException(HttpStatus.CONFLICT, "unsupported_feature", "Plan mode is unavailable");
}
requireIdlePolicyChange(session);
long current = jdbc.queryForObject("SELECT approval_revision FROM ma_session WHERE tenant_id = ?"
+ " AND session_id = ?", Long.class, tenantId, sessionId);
if (current != expectedRevision || current >= 9_007_199_254_740_991L
|| planMode && current >= 9_007_199_254_740_990L) {
throw new ApiException(HttpStatus.CONFLICT, "approval_selection_conflict", "The approval revision changed");
throw new ManagedAgentException(HttpStatus.CONFLICT, "approval_selection_conflict", "The approval revision changed");
}
long revision = current + 1;
long now = clock.millis();
@@ -4254,7 +4258,7 @@ public class ManagedAgentStore implements AgentStateStore {
requireSessionStatus(session.status(), "ACTIVE");
requireCwdChangeRegistryFacts(session);
if (hasActiveTurn(tenantId, sessionId) || hasDecidableAction(session)) {
throw new ApiException(HttpStatus.CONFLICT, "turn_active", "The Session has an active Turn or approval");
throw new ManagedAgentException(HttpStatus.CONFLICT, "turn_active", "The Session has an active Turn or approval");
}
if (hasOpenOperation(tenantId, sessionId) || hasPendingRenameDelivery(tenantId, sessionId)
|| hasRetainedRuntimeSession(tenantId, sessionId)
@@ -4263,7 +4267,7 @@ public class ManagedAgentStore implements AgentStateStore {
|| !jdbc.queryForList("SELECT 1 FROM ma_session_head WHERE tenant_id = ?"
+ " AND session_id = ? AND head_kind = 'MANAGED_SESSION' AND"
+ " (state <> 'ACTIVE' OR recovery_status <> 'READY')", tenantId, sessionId).isEmpty()) {
throw new ApiException(HttpStatus.CONFLICT, "session_context_busy", "The Session requires settlement");
throw new ManagedAgentException(HttpStatus.CONFLICT, "session_context_busy", "The Session requires settlement");
}
}
@@ -4467,7 +4471,7 @@ public class ManagedAgentStore implements AgentStateStore {
tenantId,
sessionId);
if (rows.isEmpty()) {
throw new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found.");
}
return rows.getFirst();
@@ -5500,7 +5504,7 @@ public class ManagedAgentStore implements AgentStateStore {
accepted = WorkspaceLifecycleStore.requireIdleJournal(jdbc, objectMapper,
tenantId, sessionId, false,
WorkspaceToolProfiles.lifecycleProtocol(session.toolProfile()) == 2);
} catch (ApiException unverified) {
} catch (ManagedAgentException unverified) {
return false;
}
if (accepted.contains(turn.promptId()) || !withdrawSubmissionAttempted(tenantId, sessionId, turnId, owner)) {
@@ -5634,7 +5638,7 @@ public class ManagedAgentStore implements AgentStateStore {
public SessionRecord requireSession(String tenantId, String sessionId) {
return findSession(tenantId, sessionId).orElseThrow(() ->
new ApiException(HttpStatus.NOT_FOUND, "session_not_found",
new ManagedAgentException(HttpStatus.NOT_FOUND, "session_not_found",
"The Session was not found."));
}
@@ -6112,7 +6116,7 @@ public class ManagedAgentStore implements AgentStateStore {
tenantId,
sessionId);
} catch (EmptyResultDataAccessException error) {
throw new ApiException(HttpStatus.NOT_FOUND,
throw new ManagedAgentException(HttpStatus.NOT_FOUND,
"session_not_found", "The Session was not found.");
}
}
@@ -6120,7 +6124,7 @@ public class ManagedAgentStore implements AgentStateStore {
private TurnRecord requireTurn(String tenantId, String sessionId,
String turnId) {
return findTurn(tenantId, sessionId, turnId).orElseThrow(() ->
new ApiException(HttpStatus.NOT_FOUND, "turn_not_found",
new ManagedAgentException(HttpStatus.NOT_FOUND, "turn_not_found",
"The Turn was not found."));
}
@@ -6132,7 +6136,7 @@ public class ManagedAgentStore implements AgentStateStore {
+ " turn_id = ? FOR UPDATE",
turnMapper, tenantId, sessionId, turnId);
} catch (EmptyResultDataAccessException error) {
throw new ApiException(HttpStatus.NOT_FOUND, "turn_not_found",
throw new ManagedAgentException(HttpStatus.NOT_FOUND, "turn_not_found",
"The Turn was not found.");
}
}
@@ -6288,7 +6292,7 @@ public class ManagedAgentStore implements AgentStateStore {
private void requireNoOpenOperation(String tenantId, String sessionId) {
if (hasOpenOperation(tenantId, sessionId)) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"session_operation_active",
"The Session already has a lifecycle operation in progress.");
}
@@ -6310,7 +6314,7 @@ public class ManagedAgentStore implements AgentStateStore {
if ("ACTIVE".equals(status)
&& (hasLiveTurn(session.tenantId(), session.sessionId())
|| session.workspace() != null && hasDecidableAction(session))) {
throw new ApiException(HttpStatus.CONFLICT, "turn_active",
throw new ManagedAgentException(HttpStatus.CONFLICT, "turn_active",
"The Session has an active Turn.");
}
}
@@ -6397,8 +6401,8 @@ public class ManagedAgentStore implements AgentStateStore {
}
}
private static ApiException sessionStateConflict(String status) {
return new ApiException(HttpStatus.CONFLICT,
private static ManagedAgentException sessionStateConflict(String status) {
return new ManagedAgentException(HttpStatus.CONFLICT,
"session_state_conflict",
"The Session is " + status.toLowerCase(Locale.ROOT)
+ " and cannot perform this operation.");
@@ -1,7 +1,7 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.store.ManagedToolResultStore.Artifact;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedToolResultStore.Artifact;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.http.HttpStatus;
@@ -150,7 +150,7 @@ public class ManagedArtifactReader {
private ToolPublicationDataStore data() {
var data = publications.getIfAvailable();
if (data == null) {
throw new ApiException(HttpStatus.SERVICE_UNAVAILABLE, "artifact_unavailable",
throw new ManagedAgentException(HttpStatus.SERVICE_UNAVAILABLE, "artifact_unavailable",
"Artifact storage is unavailable.");
}
return data;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionRecords.InvalidRecordException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionRecords.InvalidRecordException;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.HashSet;
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.runtimebroker.ToolExecutionRecord;
import com.fasterxml.jackson.databind.JsonNode;
@@ -1,11 +1,12 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.api.ApiException;
import com.alibaba.qwen.code.managedagent.api.ApiModels.WebShellModelContext;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionProjection.Body;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionProjection.TaskProjection;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionRecords.InvalidRecordException;
import com.alibaba.qwen.code.managedagent.store.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.exception.ManagedAgentException;
import com.alibaba.qwen.code.managedagent.model.ApiModels.WebShellModelContext;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionProjection.Body;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionProjection.TaskProjection;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionRecords.InvalidRecordException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedSessionStoreModels.StoredResource;
import com.alibaba.qwen.code.managedagent.session.AgentStateStore;
import com.alibaba.qwen.code.runtimebroker.CsiNativeActivationProof;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaKeys;
import com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaProjection;
@@ -407,7 +408,7 @@ public class ManagedExtensionRecordStore {
JsonNode record =
nativeRecords == null ? parse(lines[index]) : nativeRecords.get(index);
if (record == null) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
ManagedSessionStoreModels.ERROR_INVALID_REQUEST,
"Record line " + (index + 1) + " is not a JSON object"
+ " the Session authority can read.");
@@ -602,7 +603,7 @@ public class ManagedExtensionRecordStore {
// non-commit (an authority kept alive for the corrected
// retry), never as a write failure that latches the parent's
// Session log shut behind it.
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
"child_run_lineage_minted",
"Child run " + recordId + "'s never-started verdict does"
+ " not name the Session its creation minted.");
@@ -621,7 +622,7 @@ public class ManagedExtensionRecordStore {
for (String line : new String(bytes, StandardCharsets.UTF_8).split("\n")) {
JsonNode parsed = parse(line);
if (parsed == null) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
ManagedSessionStoreModels.ERROR_INVALID_REQUEST,
"Record line is not a JSON object the Session authority can read.");
}
@@ -686,7 +687,7 @@ public class ManagedExtensionRecordStore {
for (String line : new String(bytes, StandardCharsets.UTF_8).split("\n")) {
JsonNode parsed = parse(line);
if (parsed == null) {
throw new ApiException(HttpStatus.BAD_REQUEST,
throw new ManagedAgentException(HttpStatus.BAD_REQUEST,
ManagedSessionStoreModels.ERROR_INVALID_REQUEST,
"Record line is not a JSON object the Session authority can read.");
}
@@ -1433,7 +1434,7 @@ public class ManagedExtensionRecordStore {
taskEvents.appendStateChange(tenantId, sessionId, taskId,
projection.state(), projection.runtimeState(),
occurredAt);
} catch (ApiException refused) {
} catch (ManagedAgentException refused) {
// The record row above is the authoritative state and it is
// already written; the event journal is a derived, bounded
// feed. A journal that refuses past its backlog bound — or
@@ -1589,7 +1590,7 @@ public class ManagedExtensionRecordStore {
&& (outbound ? target == null || target.equals(parent)
: sender.equals(parent));
if (!follows) {
throw new ApiException(HttpStatus.CONFLICT, ERROR_MESSAGE_LINEAGE,
throw new ManagedAgentException(HttpStatus.CONFLICT, ERROR_MESSAGE_LINEAGE,
outbound
? "Session message to a parent must follow this"
+ " Session's lineage."
@@ -1634,7 +1635,7 @@ public class ManagedExtensionRecordStore {
boolean follows = parent != null && childRunId.equals(edge)
&& (target == null || target.equals(parent));
if (!follows) {
throw new ApiException(HttpStatus.CONFLICT,
throw new ManagedAgentException(HttpStatus.CONFLICT,
ERROR_COMMAND_LINEAGE,
"Session command to a parent must follow this"
+ " Session's lineage.");
@@ -1912,8 +1913,8 @@ public class ManagedExtensionRecordStore {
}
}
private static ApiException rejected(String message) {
return new ApiException(HttpStatus.CONFLICT, ERROR_REJECTED, message);
private static ManagedAgentException rejected(String message) {
return new ManagedAgentException(HttpStatus.CONFLICT, ERROR_REJECTED, message);
}
private record StoredRow(String domain, String recordId, long revision,
@@ -1,4 +1,4 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -1,6 +1,6 @@
package com.alibaba.qwen.code.managedagent.store;
package com.alibaba.qwen.code.managedagent.persistence;
import com.alibaba.qwen.code.managedagent.store.ManagedExtensionRecords.InvalidRecordException;
import com.alibaba.qwen.code.managedagent.persistence.ManagedExtensionRecords.InvalidRecordException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.codec.digest.DigestUtils;
Loaded 100 of 676 files, more files were not shown because too many files have changed in this diff. Show more