registry: add sqlx checks for published operation reads

This commit is contained in:
a.tolmachev
2026-04-12 21:17:56 +00:00
parent 934c872753
commit c940b9b97a
9 changed files with 966 additions and 110 deletions
@@ -0,0 +1,65 @@
{
"db_name": "PostgreSQL",
"query": "select\n id,\n operation_id,\n version,\n descriptor_kind,\n storage_ref,\n source_name,\n package_index_json,\n to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"\n from descriptors\n where operation_id = $1 and version = $2\n order by created_at asc",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "operation_id",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "version",
"type_info": "Int4"
},
{
"ordinal": 3,
"name": "descriptor_kind",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "storage_ref",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "source_name",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "package_index_json",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "created_at!",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false,
true,
true,
false,
false,
true,
true,
null
]
},
"hash": "2907637008db9d3febc5f8f2f79f7f073b35973aad326acfd54970ef0ab2a731"
}
@@ -0,0 +1,160 @@
{
"db_name": "PostgreSQL",
"query": "select\n o.id,\n o.workspace_id,\n o.name,\n o.display_name,\n o.category,\n o.protocol,\n to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",\n to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",\n to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,\n ov.version,\n ov.status,\n ov.target_json,\n ov.input_schema_json,\n ov.output_schema_json,\n ov.input_mapping_json,\n ov.output_mapping_json,\n ov.execution_config_json,\n ov.tool_description_json,\n ov.samples_json,\n ov.generated_draft_json,\n ov.config_export_json,\n ov.change_note,\n to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",\n ov.created_by\n from published_operations po\n join operation_versions ov\n on ov.operation_id = po.operation_id and ov.version = po.version\n join operations o on o.id = po.operation_id\n where po.operation_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "workspace_id",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "display_name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "category",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "protocol",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "operation_created_at!",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "operation_updated_at!",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "operation_published_at",
"type_info": "Text"
},
{
"ordinal": 9,
"name": "version",
"type_info": "Int4"
},
{
"ordinal": 10,
"name": "status",
"type_info": "Text"
},
{
"ordinal": 11,
"name": "target_json",
"type_info": "Jsonb"
},
{
"ordinal": 12,
"name": "input_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "output_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 14,
"name": "input_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 15,
"name": "output_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "execution_config_json",
"type_info": "Jsonb"
},
{
"ordinal": 17,
"name": "tool_description_json",
"type_info": "Jsonb"
},
{
"ordinal": 18,
"name": "samples_json",
"type_info": "Jsonb"
},
{
"ordinal": 19,
"name": "generated_draft_json",
"type_info": "Jsonb"
},
{
"ordinal": 20,
"name": "config_export_json",
"type_info": "Jsonb"
},
{
"ordinal": 21,
"name": "change_note",
"type_info": "Text"
},
{
"ordinal": 22,
"name": "created_at!",
"type_info": "Text"
},
{
"ordinal": 23,
"name": "created_by",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
null,
null,
null,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
null,
true
]
},
"hash": "33071dad43cffdb3bc1a55d07a5aee93f9af115155e319e49acc6f02d006fcc0"
}
@@ -0,0 +1,158 @@
{
"db_name": "PostgreSQL",
"query": "select\n o.id,\n o.workspace_id,\n o.name,\n o.display_name,\n o.category,\n o.protocol,\n to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",\n to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",\n to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,\n ov.version,\n ov.status,\n ov.target_json,\n ov.input_schema_json,\n ov.output_schema_json,\n ov.input_mapping_json,\n ov.output_mapping_json,\n ov.execution_config_json,\n ov.tool_description_json,\n ov.samples_json,\n ov.generated_draft_json,\n ov.config_export_json,\n ov.change_note,\n to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",\n ov.created_by\n from published_operations po\n join operation_versions ov\n on ov.operation_id = po.operation_id and ov.version = po.version\n join operations o on o.id = po.operation_id\n order by o.name asc",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "workspace_id",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "display_name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "category",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "protocol",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "operation_created_at!",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "operation_updated_at!",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "operation_published_at",
"type_info": "Text"
},
{
"ordinal": 9,
"name": "version",
"type_info": "Int4"
},
{
"ordinal": 10,
"name": "status",
"type_info": "Text"
},
{
"ordinal": 11,
"name": "target_json",
"type_info": "Jsonb"
},
{
"ordinal": 12,
"name": "input_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "output_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 14,
"name": "input_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 15,
"name": "output_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "execution_config_json",
"type_info": "Jsonb"
},
{
"ordinal": 17,
"name": "tool_description_json",
"type_info": "Jsonb"
},
{
"ordinal": 18,
"name": "samples_json",
"type_info": "Jsonb"
},
{
"ordinal": 19,
"name": "generated_draft_json",
"type_info": "Jsonb"
},
{
"ordinal": 20,
"name": "config_export_json",
"type_info": "Jsonb"
},
{
"ordinal": 21,
"name": "change_note",
"type_info": "Text"
},
{
"ordinal": 22,
"name": "created_at!",
"type_info": "Text"
},
{
"ordinal": 23,
"name": "created_by",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
false,
false,
false,
false,
false,
null,
null,
null,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
null,
true
]
},
"hash": "3348d60983e16bac76e81ec2158c1c6b1333ec49067d23bdd3c2fd33caa93a3c"
}
@@ -0,0 +1,23 @@
{
"db_name": "PostgreSQL",
"query": "select 1 as \"present!\"\n from workspaces w\n join agents a on a.workspace_id = w.id\n join published_agents pa on pa.agent_id = a.id\n where w.slug = $1 and a.slug = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "present!",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "3422060fba1de6d85f89c46b41cc1cf462f49f0e2fe93e9230d15f97710b74ee"
}
@@ -0,0 +1,65 @@
{
"db_name": "PostgreSQL",
"query": "select\n id,\n operation_id,\n version,\n sample_kind,\n storage_ref,\n content_type,\n file_name,\n to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"\n from operation_samples\n where operation_id = $1 and version = $2\n order by created_at asc",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "operation_id",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "version",
"type_info": "Int4"
},
{
"ordinal": 3,
"name": "sample_kind",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "storage_ref",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "content_type",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "file_name",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "created_at!",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text",
"Int4"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
true,
null
]
},
"hash": "da58664742ddda01bd0bb8fccf69c69167b1c4f4868ca5310fbd8f5fdc5cd546"
}
@@ -0,0 +1,197 @@
{
"db_name": "PostgreSQL",
"query": "select\n w.id as workspace_id,\n w.slug as workspace_slug,\n a.id as agent_id,\n a.slug as agent_slug,\n b.tool_name,\n b.tool_title,\n coalesce(b.tool_description_override, ov.tool_description_json->>'description') as \"tool_description!\",\n o.id,\n o.name,\n o.display_name,\n o.category,\n o.protocol,\n to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",\n to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",\n to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,\n ov.version,\n ov.status,\n ov.target_json,\n ov.input_schema_json,\n ov.output_schema_json,\n ov.input_mapping_json,\n ov.output_mapping_json,\n ov.execution_config_json,\n ov.tool_description_json,\n ov.samples_json,\n ov.generated_draft_json,\n ov.config_export_json,\n ov.change_note,\n to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",\n ov.created_by\n from workspaces w\n join agents a on a.workspace_id = w.id\n join published_agents pa on pa.agent_id = a.id\n join agent_operation_bindings b on b.agent_id = a.id and b.agent_version = pa.version\n join operation_versions ov on ov.operation_id = b.operation_id and ov.version = b.operation_version\n join operations o on o.id = ov.operation_id and o.workspace_id = w.id\n where w.slug = $1 and a.slug = $2 and b.enabled = true\n order by b.tool_name asc",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "workspace_slug",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "agent_id",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "agent_slug",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "tool_name",
"type_info": "Text"
},
{
"ordinal": 5,
"name": "tool_title",
"type_info": "Text"
},
{
"ordinal": 6,
"name": "tool_description!",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "id",
"type_info": "Text"
},
{
"ordinal": 8,
"name": "name",
"type_info": "Text"
},
{
"ordinal": 9,
"name": "display_name",
"type_info": "Text"
},
{
"ordinal": 10,
"name": "category",
"type_info": "Text"
},
{
"ordinal": 11,
"name": "protocol",
"type_info": "Text"
},
{
"ordinal": 12,
"name": "operation_created_at!",
"type_info": "Text"
},
{
"ordinal": 13,
"name": "operation_updated_at!",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "operation_published_at",
"type_info": "Text"
},
{
"ordinal": 15,
"name": "version",
"type_info": "Int4"
},
{
"ordinal": 16,
"name": "status",
"type_info": "Text"
},
{
"ordinal": 17,
"name": "target_json",
"type_info": "Jsonb"
},
{
"ordinal": 18,
"name": "input_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 19,
"name": "output_schema_json",
"type_info": "Jsonb"
},
{
"ordinal": 20,
"name": "input_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 21,
"name": "output_mapping_json",
"type_info": "Jsonb"
},
{
"ordinal": 22,
"name": "execution_config_json",
"type_info": "Jsonb"
},
{
"ordinal": 23,
"name": "tool_description_json",
"type_info": "Jsonb"
},
{
"ordinal": 24,
"name": "samples_json",
"type_info": "Jsonb"
},
{
"ordinal": 25,
"name": "generated_draft_json",
"type_info": "Jsonb"
},
{
"ordinal": 26,
"name": "config_export_json",
"type_info": "Jsonb"
},
{
"ordinal": 27,
"name": "change_note",
"type_info": "Text"
},
{
"ordinal": 28,
"name": "created_at!",
"type_info": "Text"
},
{
"ordinal": 29,
"name": "created_by",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
null,
false,
false,
false,
false,
false,
null,
null,
null,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
null,
true
]
},
"hash": "f7b3017dafdc3b8291e4336b2f1c8290985f30802a9c159f75b9387bf44fb611"
}
+52 -12
View File
@@ -438,7 +438,7 @@ impl PostgresRegistry {
workspace_slug: &str,
agent_slug: &str,
) -> Result<Vec<PublishedAgentTool>, RegistryError> {
let rows = sqlx::query(
let rows = sqlx::query!(
"select
w.id as workspace_id,
w.slug as workspace_slug,
@@ -446,14 +446,14 @@ impl PostgresRegistry {
a.slug as agent_slug,
b.tool_name,
b.tool_title,
coalesce(b.tool_description_override, ov.tool_description_json->>'description') as tool_description,
coalesce(b.tool_description_override, ov.tool_description_json->>'description') as \"tool_description!\",
o.id,
o.name,
o.display_name,
o.category,
o.protocol,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_created_at,
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_updated_at,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",
to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,
ov.version,
ov.status,
@@ -468,7 +468,7 @@ impl PostgresRegistry {
ov.generated_draft_json,
ov.config_export_json,
ov.change_note,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",
ov.created_by
from workspaces w
join agents a on a.workspace_id = w.id
@@ -478,22 +478,22 @@ impl PostgresRegistry {
join operations o on o.id = ov.operation_id and o.workspace_id = w.id
where w.slug = $1 and a.slug = $2 and b.enabled = true
order by b.tool_name asc",
workspace_slug,
agent_slug,
)
.bind(workspace_slug)
.bind(agent_slug)
.fetch_all(&self.pool)
.await?;
if rows.is_empty() {
let exists = sqlx::query(
"select 1
let exists = sqlx::query!(
"select 1 as \"present!\"
from workspaces w
join agents a on a.workspace_id = w.id
join published_agents pa on pa.agent_id = a.id
where w.slug = $1 and a.slug = $2",
workspace_slug,
agent_slug,
)
.bind(workspace_slug)
.bind(agent_slug)
.fetch_optional(&self.pool)
.await?;
@@ -505,6 +505,46 @@ impl PostgresRegistry {
}
}
rows.iter().map(map_published_agent_tool).collect()
rows.into_iter()
.map(|row| {
let workspace_id = row.workspace_id.clone();
build_published_agent_tool(
row.workspace_id,
row.workspace_slug,
row.agent_id,
row.agent_slug,
row.tool_name,
row.tool_title,
row.tool_description,
build_operation_version_record(
row.id,
workspace_id,
row.name,
row.display_name,
row.category,
row.protocol,
row.operation_created_at,
row.operation_updated_at,
row.operation_published_at,
row.version,
row.status,
row.target_json,
row.input_schema_json,
row.output_schema_json,
row.input_mapping_json,
row.output_mapping_json,
row.execution_config_json,
row.tool_description_json,
row.samples_json,
row.generated_draft_json,
row.config_export_json,
row.change_note,
row.created_at,
row.created_by,
)?
.snapshot,
)
})
.collect()
}
}
+141 -74
View File
@@ -665,38 +665,6 @@ fn map_operation_agent_ref(row: &PgRow) -> Result<OperationAgentRef, RegistryErr
})
}
fn map_operation_version_record(row: &PgRow) -> Result<OperationVersionRecord, RegistryError> {
build_operation_version_record(
row.try_get("id")?,
row.try_get("workspace_id")?,
row.try_get("name")?,
row.try_get("display_name")?,
row.try_get("category")?,
row.try_get("protocol")?,
row.try_get("operation_created_at")?,
row.try_get("operation_updated_at")?,
row.try_get("operation_published_at")?,
row.try_get("version")?,
row.try_get("status")?,
row.try_get::<Json<Value>, _>("target_json")?.0,
row.try_get::<Json<Value>, _>("input_schema_json")?.0,
row.try_get::<Json<Value>, _>("output_schema_json")?.0,
row.try_get::<Json<Value>, _>("input_mapping_json")?.0,
row.try_get::<Json<Value>, _>("output_mapping_json")?.0,
row.try_get::<Json<Value>, _>("execution_config_json")?.0,
row.try_get::<Json<Value>, _>("tool_description_json")?.0,
row.try_get::<Option<Json<Value>>, _>("samples_json")?
.map(|value| value.0),
row.try_get::<Option<Json<Value>>, _>("generated_draft_json")?
.map(|value| value.0),
row.try_get::<Option<Json<Value>>, _>("config_export_json")?
.map(|value| value.0),
row.try_get("change_note")?,
row.try_get("created_at")?,
row.try_get("created_by")?,
)
}
fn map_auth_profile(row: &PgRow) -> Result<AuthProfile, RegistryError> {
Ok(AuthProfile {
id: crank_core::AuthProfileId::new(row.try_get::<String, _>("id")?),
@@ -886,57 +854,74 @@ fn build_operation_version_record(
})
}
fn map_published_agent_tool(row: &PgRow) -> Result<PublishedAgentTool, RegistryError> {
let record = map_operation_version_record(row)?;
#[allow(clippy::too_many_arguments)]
fn build_published_agent_tool(
workspace_id: String,
workspace_slug: String,
agent_id: String,
agent_slug: String,
tool_name: String,
tool_title: String,
tool_description: String,
operation: RegistryOperation,
) -> Result<PublishedAgentTool, RegistryError> {
Ok(PublishedAgentTool {
workspace_id: WorkspaceId::new(row.try_get::<String, _>("workspace_id")?),
workspace_slug: row.try_get("workspace_slug")?,
agent_id: AgentId::new(row.try_get::<String, _>("agent_id")?),
agent_slug: row.try_get("agent_slug")?,
tool_name: row.try_get("tool_name")?,
tool_title: row.try_get("tool_title")?,
tool_description: row.try_get("tool_description")?,
operation: record.snapshot,
workspace_id: WorkspaceId::new(workspace_id),
workspace_slug,
agent_id: AgentId::new(agent_id),
agent_slug,
tool_name,
tool_title,
tool_description,
operation,
})
}
fn map_sample_metadata(row: &PgRow) -> Result<OperationSampleMetadata, RegistryError> {
#[allow(clippy::too_many_arguments)]
fn build_sample_metadata(
id: String,
operation_id: String,
version: i32,
sample_kind: String,
storage_ref: String,
content_type: String,
file_name: Option<String>,
created_at: String,
) -> Result<OperationSampleMetadata, RegistryError> {
Ok(OperationSampleMetadata {
id: crank_core::SampleId::new(row.try_get::<String, _>("id")?),
operation_id: OperationId::new(row.try_get::<String, _>("operation_id")?),
version: from_db_version(row.try_get("version")?, "version")?,
sample_kind: deserialize_enum_text(
&row.try_get::<String, _>("sample_kind")?,
"sample_kind",
)?,
storage_ref: row.try_get("storage_ref")?,
content_type: row.try_get("content_type")?,
file_name: row.try_get("file_name")?,
created_at: row.try_get("created_at")?,
id: crank_core::SampleId::new(id),
operation_id: OperationId::new(operation_id),
version: from_db_version(version, "version")?,
sample_kind: deserialize_enum_text(&sample_kind, "sample_kind")?,
storage_ref,
content_type,
file_name,
created_at,
})
}
fn map_descriptor_metadata(row: &PgRow) -> Result<DescriptorMetadata, RegistryError> {
#[allow(clippy::too_many_arguments)]
fn build_descriptor_metadata(
id: String,
operation_id: Option<String>,
version: Option<i32>,
descriptor_kind: String,
storage_ref: String,
source_name: Option<String>,
package_index: Option<Value>,
created_at: String,
) -> Result<DescriptorMetadata, RegistryError> {
Ok(DescriptorMetadata {
id: crank_core::DescriptorId::new(row.try_get::<String, _>("id")?),
operation_id: row
.try_get::<Option<String>, _>("operation_id")?
.map(OperationId::new),
version: row
.try_get::<Option<i32>, _>("version")?
id: crank_core::DescriptorId::new(id),
operation_id: operation_id.map(OperationId::new),
version: version
.map(|value| from_db_version(value, "version"))
.transpose()?,
descriptor_kind: deserialize_enum_text(
&row.try_get::<String, _>("descriptor_kind")?,
"descriptor_kind",
)?,
storage_ref: row.try_get("storage_ref")?,
source_name: row.try_get("source_name")?,
package_index: row
.try_get::<Option<Json<Value>>, _>("package_index_json")?
.map(|value| value.0),
created_at: row.try_get("created_at")?,
descriptor_kind: deserialize_enum_text(&descriptor_kind, "descriptor_kind")?,
storage_ref,
source_name,
package_index,
created_at,
})
}
@@ -1126,8 +1111,8 @@ mod tests {
AsyncJobFilter, CreateAgentRequest, CreateAsyncJobRequest, CreatePlatformApiKeyRequest,
CreateStreamSessionRequest, CreateVersionRequest, CreateWorkspaceRequest,
CreateYamlImportJobRequest, DescriptorKind, DescriptorMetadata,
OperationSampleMetadata, PlatformApiKeyRecord, PublishRequest, RegistryOperation,
SampleKind, SaveAuthProfileRequest, SaveDescriptorMetadataRequest,
OperationSampleMetadata, PlatformApiKeyRecord, PublishAgentRequest, PublishRequest,
RegistryOperation, SampleKind, SaveAuthProfileRequest, SaveDescriptorMetadataRequest,
SaveSampleMetadataRequest, StreamSessionFilter, UpdateAsyncJobStatusRequest,
UpdateStreamSessionStateRequest, WorkspaceRecord, YamlImportJobCompletion,
YamlImportJobId, YamlImportJobStatus,
@@ -1186,6 +1171,7 @@ mod tests {
.await
.unwrap()
.unwrap();
let published_list = registry.list_published_operations().await.unwrap();
assert_eq!(summary.current_draft_version, 2);
assert_eq!(summary.latest_published_version, Some(2));
@@ -1197,6 +1183,7 @@ mod tests {
);
assert_eq!(published.version, 2);
assert!(published.is_published());
assert_eq!(published_list, vec![published.clone()]);
database.cleanup().await;
}
@@ -1641,6 +1628,86 @@ mod tests {
database.cleanup().await;
}
#[tokio::test]
async fn manages_published_agent_tool_reads() {
let database = TestDatabase::new().await;
let registry = database.registry().await;
let operation = test_operation("op_agent_pub_01", 1, OperationStatus::Draft);
let operation_v2 = test_operation("op_agent_pub_01", 2, OperationStatus::Draft);
let agent = test_agent("agent_pub_01", AgentStatus::Draft);
let version = test_agent_version(&agent.id, 1, AgentStatus::Draft);
let bindings = vec![AgentOperationBinding {
operation_id: operation.id.clone(),
operation_version: operation_v2.version,
tool_name: "create_lead".to_owned(),
tool_title: "Create lead".to_owned(),
tool_description_override: Some("Creates CRM lead".to_owned()),
enabled: true,
}];
registry
.create_operation(&test_workspace_id(), &operation, None)
.await
.unwrap();
registry
.create_version(CreateVersionRequest {
workspace_id: &test_workspace_id(),
snapshot: &operation_v2,
change_note: Some("publishable"),
created_by: Some("alice"),
})
.await
.unwrap();
registry
.publish_operation(PublishRequest {
workspace_id: &test_workspace_id(),
operation_id: &operation.id,
version: operation_v2.version,
published_at: "2026-03-25T12:10:00Z",
published_by: Some("alice"),
})
.await
.unwrap();
registry
.create_agent(CreateAgentRequest {
agent: &agent,
version: &version,
bindings: &bindings,
})
.await
.unwrap();
registry
.publish_agent(PublishAgentRequest {
workspace_id: &test_workspace_id(),
agent_id: &agent.id,
version: version.version,
published_at: "2026-03-25T12:11:00Z",
published_by: Some("alice"),
})
.await
.unwrap();
let tools = registry
.get_published_agent_tools_by_slug("default", &agent.slug)
.await
.unwrap();
assert_eq!(tools.len(), 1);
assert_eq!(tools[0].workspace_id, test_workspace_id());
assert_eq!(tools[0].workspace_slug, "default");
assert_eq!(tools[0].agent_id, agent.id);
assert_eq!(tools[0].agent_slug, agent.slug);
assert_eq!(tools[0].tool_name, bindings[0].tool_name);
assert_eq!(tools[0].tool_title, bindings[0].tool_title);
assert_eq!(tools[0].tool_description, "Creates CRM lead");
assert_eq!(tools[0].operation.id, operation_v2.id);
assert_eq!(tools[0].operation.version, operation_v2.version);
assert_eq!(tools[0].operation.protocol, operation_v2.protocol);
assert!(tools[0].operation.is_published());
database.cleanup().await;
}
#[tokio::test]
async fn manages_stream_sessions_with_transitions_and_cleanup() {
let database = TestDatabase::new().await;
+105 -24
View File
@@ -674,7 +674,7 @@ impl PostgresRegistry {
&self,
operation_id: &OperationId,
) -> Result<Option<RegistryOperation>, RegistryError> {
let row = sqlx::query(
let row = sqlx::query!(
"select
o.id,
o.workspace_id,
@@ -682,8 +682,8 @@ impl PostgresRegistry {
o.display_name,
o.category,
o.protocol,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_created_at,
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_updated_at,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",
to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,
ov.version,
ov.status,
@@ -698,25 +698,52 @@ impl PostgresRegistry {
ov.generated_draft_json,
ov.config_export_json,
ov.change_note,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",
ov.created_by
from published_operations po
join operation_versions ov
on ov.operation_id = po.operation_id and ov.version = po.version
join operations o on o.id = po.operation_id
where po.operation_id = $1",
operation_id.as_str(),
)
.bind(operation_id.as_str())
.fetch_optional(&self.pool)
.await?;
row.as_ref()
.map(|value| map_operation_version_record(value).map(|record| record.snapshot))
.transpose()
row.map(|row| {
build_operation_version_record(
row.id,
row.workspace_id,
row.name,
row.display_name,
row.category,
row.protocol,
row.operation_created_at,
row.operation_updated_at,
row.operation_published_at,
row.version,
row.status,
row.target_json,
row.input_schema_json,
row.output_schema_json,
row.input_mapping_json,
row.output_mapping_json,
row.execution_config_json,
row.tool_description_json,
row.samples_json,
row.generated_draft_json,
row.config_export_json,
row.change_note,
row.created_at,
row.created_by,
)
.map(|record| record.snapshot)
})
.transpose()
}
pub async fn list_published_operations(&self) -> Result<Vec<RegistryOperation>, RegistryError> {
let rows = sqlx::query(
let rows = sqlx::query!(
"select
o.id,
o.workspace_id,
@@ -724,8 +751,8 @@ impl PostgresRegistry {
o.display_name,
o.category,
o.protocol,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_created_at,
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_updated_at,
to_char(o.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_created_at!\",
to_char(o.updated_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"operation_updated_at!\",
to_char(o.published_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as operation_published_at,
ov.version,
ov.status,
@@ -740,7 +767,7 @@ impl PostgresRegistry {
ov.generated_draft_json,
ov.config_export_json,
ov.change_note,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at,
to_char(ov.created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\",
ov.created_by
from published_operations po
join operation_versions ov
@@ -751,8 +778,36 @@ impl PostgresRegistry {
.fetch_all(&self.pool)
.await?;
rows.iter()
.map(|row| map_operation_version_record(row).map(|record| record.snapshot))
rows.into_iter()
.map(|row| {
build_operation_version_record(
row.id,
row.workspace_id,
row.name,
row.display_name,
row.category,
row.protocol,
row.operation_created_at,
row.operation_updated_at,
row.operation_published_at,
row.version,
row.status,
row.target_json,
row.input_schema_json,
row.output_schema_json,
row.input_mapping_json,
row.output_mapping_json,
row.execution_config_json,
row.tool_description_json,
row.samples_json,
row.generated_draft_json,
row.config_export_json,
row.change_note,
row.created_at,
row.created_by,
)
.map(|record| record.snapshot)
})
.collect()
}
@@ -802,7 +857,7 @@ impl PostgresRegistry {
operation_id: &OperationId,
version: u32,
) -> Result<Vec<OperationSampleMetadata>, RegistryError> {
let rows = sqlx::query(
let rows = sqlx::query!(
"select
id,
operation_id,
@@ -811,17 +866,30 @@ impl PostgresRegistry {
storage_ref,
content_type,
file_name,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"
from operation_samples
where operation_id = $1 and version = $2
order by created_at asc",
operation_id.as_str(),
to_db_version(version),
)
.bind(operation_id.as_str())
.bind(to_db_version(version))
.fetch_all(&self.pool)
.await?;
rows.iter().map(map_sample_metadata).collect()
rows.into_iter()
.map(|row| {
build_sample_metadata(
row.id,
row.operation_id,
row.version,
row.sample_kind,
row.storage_ref,
row.content_type,
row.file_name,
row.created_at,
)
})
.collect()
}
pub async fn save_descriptor_metadata(
@@ -876,7 +944,7 @@ impl PostgresRegistry {
operation_id: &OperationId,
version: u32,
) -> Result<Vec<DescriptorMetadata>, RegistryError> {
let rows = sqlx::query(
let rows = sqlx::query!(
"select
id,
operation_id,
@@ -885,16 +953,29 @@ impl PostgresRegistry {
storage_ref,
source_name,
package_index_json,
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as created_at
to_char(created_at at time zone 'UTC', 'YYYY-MM-DD\"T\"HH24:MI:SS\"Z\"') as \"created_at!\"
from descriptors
where operation_id = $1 and version = $2
order by created_at asc",
operation_id.as_str(),
to_db_version(version),
)
.bind(operation_id.as_str())
.bind(to_db_version(version))
.fetch_all(&self.pool)
.await?;
rows.iter().map(map_descriptor_metadata).collect()
rows.into_iter()
.map(|row| {
build_descriptor_metadata(
row.id,
row.operation_id,
row.version,
row.descriptor_kind,
row.storage_ref,
row.source_name,
row.package_index_json,
row.created_at,
)
})
.collect()
}
}