Conversation
✅ Deploy Preview for golemcloud canceled.
|
|
📖 Docs preview: https://docs-5ygaf8kbc-golem-cloud.vercel.app Built from commit |
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com> # Conflicts: # golem-worker-executor/src/worker/mod.rs
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
| let result = await_native_entity_body( | ||
| &runner_abort, | ||
| handler.invoke(retained.context_mut(), native_invocation), | ||
| ) | ||
| .await; | ||
| retained | ||
| .context_mut() | ||
| .durable_ctx_mut() | ||
| .set_invocation_principal(None); | ||
| if let Err(error) = retained.prepare_parent_end().await { | ||
| return (Err(error), Some(Box::new(retained))); | ||
| } | ||
| let result = match result { | ||
| Ok(result) => { | ||
| if let Some(error) = stdout_limit_error( | ||
| stdout_observer | ||
| .as_ref() | ||
| .and_then(AttachmentObserver::terminal_snapshot) | ||
| .is_some_and(|terminal| terminal.host_resource_exhausted), | ||
| ) { | ||
| encode_tool_operation_terminal(Err(error)).await | ||
| } else { | ||
| encode_tool_operation_terminal(result).await | ||
| } |
There was a problem hiding this comment.
Could we mirror the component invocation path's post-body
has_pending_live_admission_rejectionguard for native tools? A native handler can catch an attachment admission error and return success; this path then encodes an ordinary terminal, while the later accounting check does not replace that response with the pending resource-exhaustion failure. Please preserve the rejection before terminal encoding and cover a handler that catches the host error.
| async fn invoke( | ||
| &self, | ||
| ctx: &mut Ctx, | ||
| invocation: NativeToolInvocation, | ||
| ) -> Result<NativeToolResult, WorkerExecutorError> { | ||
| let result = self | ||
| .0 | ||
| .invoke( | ||
| ctx, | ||
| golem_native_tool::NativeToolInvocation { | ||
| command_path: invocation.command_path, | ||
| input: invocation.input, | ||
| principal: invocation.principal, | ||
| stdin: invocation.stdin.map(|input| Box::new(input) as _), | ||
| stdout: invocation.stdout.map(|output| Box::new(output) as _), | ||
| }, | ||
| ) |
There was a problem hiding this comment.
Could we expose and forward a safe cancellation handle through
golem_native_tool::NativeToolInvocation? The executor invocation carries aCancellationToken, butNativeToolAdapterconstructs the public invocation without it, so macro/SDK-authored native tools cannot observe cancellation even though direct executor handlers can. A cancellation test through the adapter would pin the supported authoring path.
| retained | ||
| .context_mut() | ||
| .durable_ctx_mut() | ||
| .set_invocation_principal(None); | ||
| if let Err(error) = retained.prepare_parent_end().await { | ||
| return (Err(error), Some(Box::new(retained))); | ||
| } | ||
| let result = match result { |
There was a problem hiding this comment.
Could we preserve the primary handler or infrastructure error when
prepare_parent_endalso fails, matching the component path? The native path currently returns the cleanup failure before examining the handler result, which can mask the failure that caused the invocation to abort. Substituting the cleanup error only when the body succeeded would retain the more useful diagnosis.
| if implementations.contains_key(&ambient.name) | ||
| || app.tool_declarations().contains_key(&ambient.name) |
There was a problem hiding this comment.
What is the intended rollout policy when a future Golem release introduces an ambient tool whose name is already used by an application or selected account-owned tool? AFAIU existing deployments remain intact, but the next deployment will fail. I guess this is fine (and similar to account shared ones), just wanted to double check.
| @@ -1 +1 @@ | |||
| 9b8236ff15b23a2da0c9bbaaa28149cd9875f93d6a519dab7b5ed98c8dbdfd75 | |||
| 8432554acdeedaabbb278c764a8a66243102ea9197309ffa6248071564c9a3c3 | |||
There was a problem hiding this comment.
This should bump the diff model version, and create a v6 fingerprint
| // Ambient tools are registry-owned input. Resolve them before local validation and | ||
| // hashing; planning remains read-only. | ||
| let ambient_plan = self | ||
| .ctx | ||
| .golem_clients() | ||
| .await? | ||
| .environment | ||
| .get_environment_deployment_plan(&environment.environment_id.0) | ||
| .await | ||
| .map_service_error()?; |
There was a problem hiding this comment.
prepare_deploymentnow fetches the same deployment plan twice; I think one read should be enough (also the first read calls itambient_plan, which is not entirely correct)ambientToolsappears to be the first field in this DTO that is not information identifying or describing the staged diff side itself, but is auxiliary registry metadata used to construct the proposed side, so i think it would be clearer to separate it explicitly in the response DTO (or have some comment on it / naming convention for possible future similar ones?)
| #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] | ||
| #[serde(untagged)] | ||
| pub enum ManifestConfigKeyScope { | ||
| All(String), | ||
| Keys(Vec<String>), | ||
| } |
There was a problem hiding this comment.
Some of our checks are only visible in the JSON schema, but that is extra meta, not the main validation we use in the CLI:
The JSON Schema constraints are useful diagnostics, but they are not currently enforced by Rust when the manifest deserializes successfully: the untagged scope enums accept any string and any string list, while path validation happens only during deployment. Please enforce the wildcard/list shape through serde and validate every path while loading/building the application in
app_raw.rsorapp.rs. The same issue exists for the pre-existing secret scopes, and the generic audit also found that tool-binding keys rely on the schema regex without equivalent Rust load-time validation.
| "items": { | ||
| "type": "string", | ||
| "not": { | ||
| "const": "*" | ||
| } | ||
| } | ||
| } | ||
| ] | ||
| }, |
There was a problem hiding this comment.
It seems we keep modifying these dev one, unlike how they were originally intended to be used. I guess this can be the new norm, but we might want to adjust the skills so we do not modify non dev versions. And we might want to think about automating the publishing of these, to guarantee no update on the non dev one (not in this PR, just want to mention).
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
| pub struct DeploymentPlanAmbientToolEntry { | ||
| pub release_id: crate::model::tool_release::ToolReleaseId, | ||
| pub name: ToolName, | ||
| pub version: String, |
There was a problem hiding this comment.
Define either a new transparent newtype for this like DeploymentVersion or use that, if appropriate. Same applies for metadata_version below.
| #[test] | ||
| async fn can_extract_tool_metadata_from_component_bytes() -> anyhow::Result<()> { | ||
| let wasm = std::fs::read( | ||
| "../test-components/tool-streaming/golem-temp/agents/golem_it_tool_streaming_rust_provider_release.wasm", |
There was a problem hiding this comment.
Should not use a temp build dir - use the wasm from ../test-components where the test component build script places it
| pub environment_state_service: Arc<EnvironmentStateService>, | ||
| pub http_api_deployment_service: Arc<HttpApiDeploymentService>, | ||
| pub mcp_deployment_service: Arc<McpDeploymentService>, | ||
| pub native_tool_catalog: Arc<crate::services::native_tool_catalog::NativeToolCatalog>, |
There was a problem hiding this comment.
Why not import the trait - don't use fully qualified paths where not necessary (not just this line)
| let mut registrations = vec![NativeToolRegistration { | ||
| definition: native_test_helper_definition(), | ||
| handler: Arc::new(NativeToolAdapter( | ||
| __GolemNativeToolInvokerNativeDurableHelperImplNativeDurableHelper::new( |
There was a problem hiding this comment.
What is this horrible type name and (if it is macro generated) why do we need to explicitly use here? Let's avoid that
| /// conformance of these literals against their referenced type node is checked | ||
| /// separately by [`validate_tool`], which has the per-command field context | ||
| /// needed to resolve `value-is` references. | ||
| #[cfg(any())] |
There was a problem hiding this comment.
There are 12 #[cfg(any())] blocks in this file (none existed before the move). That is dead code that is merely compiled out — delete it instead. We do not keep old code paths around (see the backward-compatibility section in AGENTS.md).
| &deployment_write_service, | ||
| &tool_release_service, | ||
| ) | ||
| .await |
There was a problem hiding this comment.
Built-in tool provisioning failure aborts registry startup here, while built-in plugin provisioning just above only warns. Pick one behaviour deliberately for both. Hard-failing is arguably right for protected system releases, but then the plugin path should match (or the difference should be documented).
| @@ -120,11 +120,6 @@ impl ToolReleaseRecord { | |||
| "system tool release coordinate does not match its definition" | |||
There was a problem hiding this comment.
The "protected system tool releases must use a host source" check was removed here so that component-implemented built-ins can also be protected system releases. Nothing now enforces the source/availability pairing though: Ambient ⇒ Host source and Grantable ⇒ Component source. Please reinstate that invariant in its new form (here or in ToolReleaseService::provision_system_release).
|
|
||
| static NATIVE_TEST_EFFECTS: AtomicUsize = AtomicUsize::new(0); | ||
| static NATIVE_TEST_HELPER_EFFECTS: AtomicUsize = AtomicUsize::new(0); | ||
| static NATIVE_TEST_TOOL_METADATA: OnceLock<golem_common::schema::tool::Tool> = OnceLock::new(); |
There was a problem hiding this comment.
Process-global mutable state in test utils (OnceLock + install_native_test_tool_metadata) makes the native test tool registration depend on which test ran first in the process and leaks between tests. Register test tools explicitly on the test context/catalog instead — this goes away naturally once the catalog is a bootstrap-time service passed into the context rather than a static fn.
| let ordinary_remote_tools = data | ||
| .remote_tools | ||
| .iter() | ||
| .filter(|deployment| !ambient_catalog.contains_key(&deployment.name)) |
There was a problem hiding this comment.
The CLI rejects a top-level tools entry whose name collides with an ambient tool, but the API silently accepts it: the user's release/provision/environment_binding is dropped here and replaced with the ambient one, and only agent_bindings survive. The server should reject the collision too (or at least error when the requested release differs from the ambient release) instead of rewriting the request.
| crate::services::environment_tool_grant::ResolvedGrantedToolRelease { | ||
| owner: AccountSummary { | ||
| id: release.owner_account_id, | ||
| name: "Golem system".to_string(), |
There was a problem hiding this comment.
Hardcoded display name; take it from the actual built-in tool owner account instead of a literal.
Amp-Thread-ID: https://ampcode.com/threads/T-01a07abb-341e-76cc-9a80-cbd07ef73745 Co-authored-by: Amp <amp@ampcode.com>
Resolves GOL-24