0c5b140d29
CI / push-validation (pull_request) Successful in 18s
CI / lint (pull_request) Successful in 26s
CI / helm (pull_request) Successful in 38s
CI / build (pull_request) Successful in 48s
CI / quality (pull_request) Successful in 54s
CI / security (pull_request) Successful in 55s
CI / typecheck (pull_request) Successful in 57s
CI / e2e_tests (pull_request) Successful in 4m48s
CI / unit_tests (pull_request) Successful in 8m5s
CI / integration_tests (pull_request) Successful in 9m23s
CI / docker (pull_request) Successful in 1m23s
CI / coverage (pull_request) Successful in 12m29s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / status-check (pull_request) Successful in 1s
CI / push-validation (push) Successful in 12s
CI / helm (push) Successful in 29s
CI / build (push) Successful in 3m23s
CI / lint (push) Successful in 3m38s
CI / quality (push) Successful in 3m40s
CI / security (push) Successful in 4m3s
CI / typecheck (push) Successful in 4m5s
CI / e2e_tests (push) Successful in 6m42s
CI / unit_tests (push) Successful in 10m7s
CI / integration_tests (push) Successful in 10m13s
CI / docker (push) Successful in 1m46s
CI / coverage (push) Successful in 10m58s
CI / status-check (push) Successful in 2s
Move alembic configuration and migration files from repository root into the Python package structure to ensure they are included in the wheel distribution. This fix resolves the FileNotFoundError when running `agents init` in Docker containers or any environment using the built wheel distribution. Changes: - Move alembic/ directory from repo root to src/cleveragents/infrastructure/database/migrations/ - Move alembic.ini to the same new location and update script_location setting - Update MigrationRunner._find_alembic_ini() to search from the new canonical location within the package - Update create_template_db.py to point to the new alembic.ini location - Update documentation references to reflect new migration file locations - Create __init__.py for migrations package - The env.py file is imported when running tests that verify all modules can be imported without errors. However, context.config is only available when alembic is actually running migrations, not during normal module imports. This caused an AttributeError when the test tried to import the migrations.env module. - Fix by using getattr() with a default value to safely access context.config, and guard all code that uses config with None checks. This allows the module to be safely imported while still functioning correctly during migrations. Testing: - Verified MigrationRunner can locate alembic.ini in new location - Tested agents init succeeds in creating project with database - Template database creation works correctly - All migration tests should pass without changes Alembic files now follow standard Python packaging conventions, making them automatically included in wheel distributions without special configuration. ISSUES CLOSED: #4180
212 lines
10 KiB
Markdown
212 lines
10 KiB
Markdown
# Resource Registry
|
|
|
|
The Resource Registry manages **resource types** and **resource
|
|
instances** in CleverAgents. Resource types define schemas, sandbox
|
|
strategies, and handler implementations. Resource instances are
|
|
registered entries that plans operate on during execution.
|
|
|
|
## Built-in Resource Types
|
|
|
|
CleverAgents ships with two built-in types, available without
|
|
registration:
|
|
|
|
| Type | Kind | Sandbox Strategy | Handler |
|
|
|------------------|----------|------------------|--------------------------------|
|
|
| `git-checkout` | physical | `git_worktree` | `GitCheckoutHandler` |
|
|
| `fs-directory` | physical | `copy_on_write` | `FsDirectoryHandler` |
|
|
|
|
Built-in types are registered idempotently at startup via
|
|
`ResourceRegistryService.bootstrap_builtin_types()`.
|
|
|
|
## Resource Type Fields
|
|
|
|
Each `ResourceTypeSpec` defines a resource type schema:
|
|
|
|
| Field | Type | Description |
|
|
|--------------------|---------------------|------------------------------------------------------|
|
|
| `name` | `str` | Unique name (built-in: bare, custom: `namespace/name`) |
|
|
| `description` | `str` | Human-readable description |
|
|
| `resource_kind` | `ResourceKind` | `physical` or `virtual` |
|
|
| `sandbox_strategy` | `SandboxStrategy` | Default sandbox isolation strategy |
|
|
| `user_addable` | `bool` | Whether users can register instances of this type |
|
|
| `built_in` | `bool` | Whether this is a built-in type |
|
|
| `cli_args` | `list[ResourceTypeArgument]` | CLI argument definitions for registration |
|
|
| `parent_types` | `list[str]` | Allowed parent type names in the DAG |
|
|
| `child_types` | `list[str]` | Allowed child type names in the DAG |
|
|
| `handler` | `str \| None` | Handler ref in `module:Class` format |
|
|
| `capabilities` | `dict[str, bool]` | `read`, `write`, `sandbox`, `checkpoint` flags |
|
|
| `auto_discovery` | `dict \| None` | Auto-discovery rules (see below) |
|
|
| `equivalence` | `dict \| None` | Virtual resource deduplication config |
|
|
|
|
### Custom Types
|
|
|
|
Custom types are defined in YAML and registered via CLI or API:
|
|
|
|
```yaml
|
|
name: myteam/python-package
|
|
description: A Python package directory
|
|
resource_kind: physical
|
|
sandbox_strategy: copy_on_write
|
|
user_addable: true
|
|
cli_args:
|
|
- name: path
|
|
type: path
|
|
required: true
|
|
description: Path to the package root
|
|
parent_types:
|
|
- git-checkout
|
|
child_types:
|
|
- fs-directory
|
|
```
|
|
|
|
Register with: `agents resource type add path/to/type.yaml`
|
|
|
|
## Resource Instance Fields
|
|
|
|
Each `Resource` represents a registered asset:
|
|
|
|
| Field | Type | Description |
|
|
|----------------------|-----------------------|----------------------------------------------|
|
|
| `resource_id` | `str` (ULID) | Unique identifier |
|
|
| `name` | `str \| None` | Optional namespaced name |
|
|
| `resource_type_name` | `str` | Type this resource belongs to |
|
|
| `classification` | `PhysVirt` | `physical` or `virtual` |
|
|
| `description` | `str \| None` | Human-readable description |
|
|
| `location` | `str \| None` | Filesystem path (physical resources) |
|
|
| `sandbox_strategy` | `SandboxStrategy \| None` | Per-resource sandbox override |
|
|
| `content_hash` | `str \| None` | Hash of resource contents for change detection |
|
|
| `parents` | `list[str]` | Parent resource IDs in the DAG |
|
|
| `children` | `list[str]` | Child resource IDs in the DAG |
|
|
| `properties` | `dict` | Type-specific key-value properties |
|
|
| `capabilities` | `ResourceCapabilities`| `readable`, `writable`, `sandboxable`, `checkpointable` |
|
|
| `created_at` | `datetime` | Registration timestamp |
|
|
| `updated_at` | `datetime` | Last modification timestamp |
|
|
|
|
## Registry Service API
|
|
|
|
### Type Operations
|
|
|
|
| Method | Description |
|
|
|-------------------------|------------------------------------------|
|
|
| `bootstrap_builtin_types()` | Register built-in types (idempotent) |
|
|
| `register_type(config_path)` | Register a custom type from YAML |
|
|
| `list_types(namespace=)` | List types, optionally filtered |
|
|
| `show_type(name)` | Get a type by name |
|
|
|
|
### Resource Operations
|
|
|
|
| Method | Description |
|
|
|-------------------------------|--------------------------------------|
|
|
| `register_resource(type_name, name=, location=, ...)` | Create and register an instance |
|
|
| `list_resources(type_name=)` | List resources, optionally by type |
|
|
| `show_resource(name_or_id)` | Get by namespaced name or ULID |
|
|
|
|
### DAG Operations
|
|
|
|
| Method | Description |
|
|
|---------------------------------|------------------------------------|
|
|
| `link_child(parent, child)` | Link a child to a parent |
|
|
| `unlink_child(parent, child)` | Remove a parent-child link |
|
|
| `get_children(name_or_id)` | Get direct children |
|
|
| `get_resource_tree(name_or_id, depth=, type_filter=)` | Recursive tree traversal |
|
|
|
|
For DAG rules, cycle detection, type compatibility, and auto-discovery
|
|
details, see [Resource DAG](resource_dag.md).
|
|
|
|
## Discovery Behavior
|
|
|
|
### Auto-Discovery
|
|
|
|
Resource types can define auto-discovery rules that materialize child
|
|
resources automatically:
|
|
|
|
```yaml
|
|
auto_discovery:
|
|
enabled: true
|
|
rules:
|
|
- type: fs-directory
|
|
pattern: "*/"
|
|
- type: fs-file
|
|
pattern: "*"
|
|
```
|
|
|
|
When `auto_discover_children(resource_id)` is called:
|
|
|
|
1. The resource and its type are looked up.
|
|
2. Each discovery rule is evaluated:
|
|
- The child type must exist in the registry.
|
|
- The child type must be compatible with the parent type (per
|
|
`child_types`).
|
|
3. New child resources are created with `auto_discovered = true`.
|
|
4. Links are created in the `resource_links` table.
|
|
|
|
Auto-discovery is triggered:
|
|
- When a resource is first registered
|
|
- When resource contents change
|
|
- On demand via CLI (`agents resource discover`)
|
|
|
|
### Local-Mode Discovery
|
|
|
|
In local mode (the default), discovery operates against the local
|
|
filesystem. The registry creates placeholder resource entries based
|
|
on discovery rules; actual file enumeration is delegated to resource
|
|
handlers at sandbox creation time.
|
|
|
|
## Database Schema
|
|
|
|
### `resource_types` Table
|
|
|
|
| Column | Type | Description |
|
|
|---------------------------|---------------|--------------------------------|
|
|
| `name` | `String(128)` | Primary key |
|
|
| `namespace` | `String(64)` | Namespace (or `builtin`) |
|
|
| `description` | `Text` | Human-readable description |
|
|
| `resource_kind` | `String(16)` | `physical` or `virtual` |
|
|
| `sandbox_strategy` | `String(32)` | Default sandbox strategy |
|
|
| `user_addable` | `Boolean` | User registration allowed |
|
|
| `built_in` | `Boolean` | Built-in type flag |
|
|
| `handler` | `String(256)` | Handler `module:Class` ref |
|
|
| `args_schema_json` | `Text` | CLI args JSON |
|
|
| `allowed_parent_types_json` | `Text` | Allowed parent types JSON |
|
|
| `allowed_child_types_json` | `Text` | Allowed child types JSON |
|
|
| `auto_discover_json` | `Text` | Auto-discovery config JSON |
|
|
| `capabilities_json` | `Text` | Capabilities JSON |
|
|
| `equivalence_json` | `Text` | Equivalence config JSON |
|
|
| `source` | `String(256)` | Registration source |
|
|
| `created_at` | `String(30)` | ISO-8601 timestamp |
|
|
| `updated_at` | `String(30)` | ISO-8601 timestamp |
|
|
|
|
### `resources` Table
|
|
|
|
| Column | Type | Description |
|
|
|--------------------|---------------|-------------------------------------|
|
|
| `resource_id` | `String(26)` | ULID primary key |
|
|
| `namespaced_name` | `String(256)` | Optional namespaced name (unique) |
|
|
| `namespace` | `String(64)` | Namespace extracted from name |
|
|
| `type_name` | `String(128)` | FK to `resource_types.name` |
|
|
| `resource_kind` | `String(16)` | `physical` or `virtual` |
|
|
| `location` | `Text` | Filesystem path |
|
|
| `description` | `Text` | Human-readable description |
|
|
| `read_only` | `Boolean` | Read-only flag |
|
|
| `auto_discovered` | `Boolean` | Created by auto-discovery |
|
|
| `sandbox_strategy` | `String(32)` | Per-resource sandbox override |
|
|
| `content_hash` | `String(128)` | Content hash for change detection |
|
|
| `properties_json` | `Text` | Type-specific properties JSON |
|
|
| `metadata_json` | `Text` | Additional metadata JSON |
|
|
| `created_at` | `String(30)` | ISO-8601 timestamp |
|
|
| `updated_at` | `String(30)` | ISO-8601 timestamp |
|
|
|
|
### `resource_links` Table
|
|
|
|
See [Resource DAG](resource_dag.md#database-schema) for link table
|
|
schema.
|
|
|
|
## Source
|
|
|
|
- Domain models: `src/cleveragents/domain/models/core/resource.py`,
|
|
`resource_type.py`
|
|
- Service: `src/cleveragents/application/services/resource_registry_service.py`
|
|
- Migration: `src/cleveragents/infrastructure/database/migrations/versions/b1_001_resource_registry_tables.py`
|
|
- CLI: `src/cleveragents/cli/commands/resource.py`
|
|
- Specification: `docs/specification.md` — Resource Registry sections
|