From cb617d80128b7f2020cfcd2b0992b272f65ec9e1 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Wed, 30 Sep 2026 10:41:27 +0000 Subject: [PATCH 1/2] Move the daemon gateway and device packages into Core Only Core uses internal/agentdaemon/gateway and internal/agentdaemon/device in production, so they now live at services/core/internal/runtimegateway and services/core/internal/runtimedevice. internal/agentdaemon/proto stays shared. The daemon's WebSocket contract test imported Core's gateway directly and cannot cross Go's internal-package boundary any more; it is removed here and replaced by shared-scenario conformance tests in the next commit. The gateway's swag annotations are removed: the moved handler is now inside the OpenAPI scan, and these routes are documented as having no generated schema. --- Makefile | 2 +- .../daemon/internal/contracttest/wire_test.go | 382 ------------------ docs/runtime-protocol.md | 2 +- scripts/build-core.sh | 2 +- scripts/name-allowlist.json | 5 - services/core/IMPLEMENTATION.md | 2 +- services/core/cmd/device/main.go | 4 +- services/core/cmd/server/core_metrics.go | 4 +- .../core/cmd/server/daemon_bootstrap_test.go | 14 +- services/core/cmd/server/http_routes_test.go | 6 +- services/core/cmd/server/main.go | 4 +- .../core/internal/api/admin_resources_test.go | 8 +- .../core/internal/api/admin_runtime_test.go | 4 +- .../api/admin_session_archive_test.go | 4 +- services/core/internal/api/auth_test.go | 8 +- .../core/internal/api/contract_routes_test.go | 4 +- .../core/internal/api/core_errors_test.go | 4 +- .../core/internal/api/core_metrics_test.go | 4 +- .../api/core_store_validation_test.go | 4 +- .../internal/api/environment_creation_test.go | 4 +- .../environment_executor_management_test.go | 8 +- .../api/environment_files_create_test.go | 6 +- .../internal/api/environment_files_test.go | 4 +- .../api/environment_installation_test.go | 4 +- .../core/internal/api/environments_test.go | 4 +- .../core/internal/api/hosted_failure_test.go | 4 +- .../core/internal/api/installation_test.go | 6 +- .../internal/api/project_api_keys_test.go | 6 +- .../core/internal/api/resource_query_test.go | 6 +- services/core/internal/api/routing_test.go | 20 +- .../sandbox_configuration_discovery_test.go | 4 +- .../api/sandbox_deployment_changes_test.go | 4 +- .../api/sandbox_deployment_setup_test.go | 4 +- .../core/internal/api/sandbox_manager_test.go | 12 +- .../internal/api/sandbox_node_detail_test.go | 4 +- .../api/session_creation_stream_test.go | 6 +- .../api/session_environment_http_test.go | 4 +- .../internal/api/stream_authority_test.go | 4 +- services/core/internal/api/stream_test.go | 4 +- services/core/internal/api/vaults_test.go | 4 +- .../core/internal/api/write_audit_test.go | 4 +- .../archive_cancellation_cleanup_test.go | 16 +- services/core/internal/execution/artifacts.go | 4 +- services/core/internal/execution/delivery.go | 10 +- .../internal/execution/device_authority.go | 8 +- .../execution/directory_preparation.go | 6 +- .../internal/execution/disabled_tools_test.go | 6 +- .../core/internal/execution/dispatcher.go | 4 +- .../execution/environment_directory.go | 4 +- .../execution/executor_preparation.go | 4 +- .../execution/function_images_test.go | 4 +- services/core/internal/execution/functions.go | 6 +- .../core/internal/execution/mcp_support.go | 4 +- .../internal/execution/mcp_support_test.go | 6 +- .../internal/execution/message_support.go | 6 +- .../execution/model_execution_test.go | 8 +- .../core/internal/execution/preparation.go | 8 +- .../core/internal/execution/recovery_test.go | 4 +- services/core/internal/execution/request.go | 4 +- .../execution/runtime_compute_wake.go | 4 +- .../internal/execution/runtime_connections.go | 10 +- .../execution/runtime_initialization.go | 4 +- .../internal/execution/runtime_lifecycle.go | 12 +- .../internal/execution/runtime_manager.go | 4 +- .../sandbox_deployment_drain_test.go | 6 +- .../sandbox_deployment_setup_test.go | 14 +- .../sandbox_deployment_switch_test.go | 10 +- .../execution/sandbox_generations_test.go | 4 +- .../sandbox_provider_contract_test.go | 4 +- .../internal/execution/sandbox_reset_test.go | 4 +- .../execution/sandbox_snapshot_budget_test.go | 4 +- .../execution/structured_output_test.go | 4 +- services/core/internal/execution/support.go | 14 +- services/core/internal/runtime/gateway.go | 18 +- .../internal/runtimedevice}/cancellation.go | 2 +- .../internal/runtimedevice}/credential.go | 2 +- .../core/internal/runtimedevice}/state.go | 2 +- .../internal/runtimeenrollment/connection.go | 14 +- .../runtimeenrollment/connection_test.go | 26 +- .../internal/runtimeenrollment/enrollment.go | 4 +- .../runtimeenrollment/enrollment_test.go | 4 +- .../core/internal/runtimegateway}/auth.go | 8 +- .../internal/runtimegateway}/auth_test.go | 20 +- .../runtimegateway}/bootstrap_url_test.go | 6 +- .../internal/runtimegateway}/cancellation.go | 6 +- .../runtimegateway}/cancellation_test.go | 16 +- .../runtimegateway}/capabilities_test.go | 6 +- .../runtimegateway}/chunk_exchange.go | 2 +- .../runtimegateway}/functions_test.go | 2 +- .../core/internal/runtimegateway}/handler.go | 54 +-- .../internal/runtimegateway}/handler_test.go | 8 +- .../mcp_bearer_fixture_linux_test.go | 2 +- .../mcp_bearer_live_linux_test.go | 6 +- .../mcp_bearer_process_linux_test.go | 2 +- .../core/internal/runtimegateway}/mcp_test.go | 2 +- .../core/internal/runtimegateway}/owner.go | 12 +- .../internal/runtimegateway}/owner_test.go | 18 +- .../internal/runtimegateway}/preparation.go | 2 +- .../runtimegateway}/preparation_test.go | 2 +- .../core/internal/runtimegateway}/registry.go | 2 +- .../internal/runtimegateway}/registry_test.go | 2 +- .../core/internal/runtimegateway}/routes.go | 2 +- .../runtimegateway}/runtime_prepare.go | 2 +- .../runtimegateway}/runtime_prepare_test.go | 2 +- .../core/internal/runtimegateway}/session.go | 36 +- .../internal/runtimegateway}/session_test.go | 24 +- .../internal/runtimegateway}/subscription.go | 2 +- .../runtimegateway}/subscription_test.go | 2 +- .../internal/runtimegateway}/suspension.go | 2 +- .../runtimegateway}/suspension_test.go | 2 +- .../workspace_directory_test.go | 2 +- .../runtimegateway}/workspace_export.go | 2 +- .../runtimegateway}/workspace_export_test.go | 2 +- .../runtimegateway}/workspace_read.go | 2 +- .../runtimegateway}/workspace_read_test.go | 2 +- .../runtimegateway}/workspace_write.go | 2 +- .../runtimegateway}/workspace_write_test.go | 2 +- .../providers/configuration_flow_test.go | 4 +- .../store/admin_session_archive_test.go | 8 +- .../admin_session_archive_worker_http_test.go | 8 +- .../agent_execution_defaults_http_test.go | 4 +- .../store/agents_delete_public_test.go | 6 +- .../store/agents_update_public_test.go | 6 +- .../store/archive_cancellation_test.go | 16 +- .../configuration_validation_public_test.go | 6 +- .../creation_stream_settlement_public_test.go | 4 +- .../store/credential_matrix_http_test.go | 10 +- .../deployment_model_providers_http_test.go | 10 +- .../store/device_bootstrap_binding_test.go | 16 +- services/core/internal/store/devices.go | 28 +- services/core/internal/store/devices_test.go | 10 +- services/core/internal/store/dispatch_test.go | 10 +- .../store/environment_claim_worker_test.go | 4 +- .../environment_connection_worker_test.go | 4 +- .../environment_executor_command_test.go | 8 +- .../store/environment_expiry_worker_test.go | 4 +- ...onment_file_write_semantics_public_test.go | 6 +- .../store/environment_file_writes_test.go | 4 +- .../store/environment_initial_public_test.go | 6 +- .../store/environment_initialization_test.go | 12 +- .../store/environment_mcp_public_test.go | 4 +- .../store/environment_retrieve_public_test.go | 8 +- .../store/environment_runtime_fixture_test.go | 4 +- .../internal/store/execution_lease_test.go | 4 +- .../file_resource_semantics_public_test.go | 6 +- .../store/function_images_native_test.go | 6 +- .../store/function_inputs_public_test.go | 4 +- .../store/function_public_native_test.go | 4 +- .../store/function_state_public_test.go | 4 +- .../internal/store/harness_onboarding_test.go | 4 +- ...sted_initialization_failure_public_test.go | 10 +- .../internal/store/initial_files_http_test.go | 4 +- .../store/input_conflicts_public_test.go | 6 +- .../internal/store/list_cursor_public_test.go | 8 +- .../internal/store/list_query_public_test.go | 6 +- .../store/local_environment_devices_test.go | 8 +- .../store/mcode_public_native_test.go | 6 +- .../mcp_credential_selection_public_test.go | 6 +- .../store/message_images_native_test.go | 6 +- .../store/model_protocol_native_test.go | 4 +- .../store/native_public_execution_test.go | 4 +- .../store/path_id_semantics_public_test.go | 6 +- .../store/project_api_keys_http_test.go | 4 +- .../core/internal/store/remote_mcp_test.go | 4 +- .../store/request_body_public_test.go | 8 +- .../internal/store/runtime_adoption_test.go | 6 +- .../store/runtime_allocations_test.go | 20 +- .../internal/store/runtime_cancellation.go | 16 +- .../store/runtime_compute_lifecycle_test.go | 8 +- .../internal/store/runtime_deployment_test.go | 18 +- .../store/runtime_deployment_worker_test.go | 4 +- .../internal/store/runtime_enrollment_test.go | 12 +- .../runtime_environment_terminal_test.go | 6 +- .../internal/store/runtime_idle_clock_test.go | 4 +- .../store/runtime_initialization_peer_test.go | 6 +- .../store/runtime_lifecycle_nodes_test.go | 6 +- .../internal/store/runtime_lifecycle_test.go | 12 +- .../store/runtime_node_generations_test.go | 4 +- .../runtime_node_lifecycle_fixture_test.go | 10 +- .../core/internal/store/runtime_nodes_test.go | 10 +- .../store/runtime_observation_test.go | 4 +- .../internal/store/runtime_pending_test.go | 4 +- .../internal/store/runtime_suspension_test.go | 8 +- .../sandbox_deployment_resources_test.go | 4 +- .../store/sandbox_deployment_switch_test.go | 6 +- .../sandbox_deployment_switch_worker_test.go | 4 +- .../store/sandbox_deployment_worker_test.go | 4 +- .../sandbox_node_auth_order_http_test.go | 4 +- .../store/sandbox_specification_store_test.go | 10 +- .../store/saved_web_search_public_test.go | 6 +- .../store/self_hosted_cancel_public_test.go | 6 +- .../store/self_hosted_initial_public_test.go | 12 +- .../store/session_agent_filter_public_test.go | 6 +- .../store/session_artifacts_public_test.go | 6 +- .../session_deletion_lifecycle_public_test.go | 8 +- .../store/session_deletion_public_test.go | 6 +- .../store/session_diagnostics_test.go | 4 +- .../session_execution_configuration_test.go | 4 +- .../store/session_initial_public_test.go | 4 +- .../session_model_execution_http_test.go | 4 +- .../session_reference_retry_public_test.go | 4 +- .../store/skill_selectors_public_test.go | 6 +- .../skill_version_deletion_public_test.go | 6 +- .../core/internal/store/skills_public_test.go | 6 +- .../store/source_files_errors_public_test.go | 6 +- .../store/structured_output_native_test.go | 6 +- .../store/subagent_identities_test.go | 4 +- .../store/subagent_native_outputs_test.go | 6 +- .../internal/store/subagent_resources_test.go | 4 +- .../store/subagent_visibility_public_test.go | 8 +- .../store/template_composition_public_test.go | 6 +- .../template_null_selection_public_test.go | 6 +- .../internal/store/tool_policy_native_test.go | 6 +- .../internal/store/tool_search_native_test.go | 6 +- .../unified_model_configuration_http_test.go | 6 +- .../store/unstorable_text_public_test.go | 4 +- .../store/whitespace_input_public_test.go | 10 +- 217 files changed, 701 insertions(+), 1128 deletions(-) delete mode 100644 apps/daemon/internal/contracttest/wire_test.go rename {internal/agentdaemon/device => services/core/internal/runtimedevice}/cancellation.go (95%) rename {internal/agentdaemon/device => services/core/internal/runtimedevice}/credential.go (97%) rename {internal/agentdaemon/device => services/core/internal/runtimedevice}/state.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/auth.go (92%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/auth_test.go (85%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/bootstrap_url_test.go (78%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/cancellation.go (95%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/cancellation_test.go (88%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/capabilities_test.go (93%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/chunk_exchange.go (96%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/functions_test.go (97%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/handler.go (80%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/handler_test.go (91%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/mcp_bearer_fixture_linux_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/mcp_bearer_live_linux_test.go (96%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/mcp_bearer_process_linux_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/mcp_test.go (98%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/owner.go (53%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/owner_test.go (79%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/preparation.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/preparation_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/registry.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/registry_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/routes.go (97%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/runtime_prepare.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/runtime_prepare_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/session.go (94%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/session_test.go (95%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/subscription.go (98%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/subscription_test.go (98%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/suspension.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/suspension_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_directory_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_export.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_export_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_read.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_read_test.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_write.go (99%) rename {internal/agentdaemon/gateway => services/core/internal/runtimegateway}/workspace_write_test.go (99%) diff --git a/Makefile b/Makefile index 2a8dbcf4b..95bfcf238 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ check-go: .PHONY: check-runtime-contract check-runtime-contract: - go test ./internal/agentdaemon/proto ./internal/agentdaemon/gateway ./apps/daemon/internal/transport ./apps/daemon/internal/dispatch ./apps/daemon/internal/contracttest -count=1 + go test ./internal/agentdaemon/proto ./services/core/internal/runtimegateway ./apps/daemon/internal/transport ./apps/daemon/internal/dispatch -count=1 go test ./services/core/internal/execution -run '^TestRuntimeProtocol' -count=1 go test ./apps/daemon/internal/agent/... -run '^(TestSharedTextLifecycle|TestPublicHarnessContractDeclarations|TestRegistryRejectsEveryOmittedCapabilityBeforeReplacement|TestUnsupportedExtensionsHaveNoNativeEffects)$$' -count=1 diff --git a/apps/daemon/internal/contracttest/wire_test.go b/apps/daemon/internal/contracttest/wire_test.go deleted file mode 100644 index 9e4586c3a..000000000 --- a/apps/daemon/internal/contracttest/wire_test.go +++ /dev/null @@ -1,382 +0,0 @@ -// Package contracttest exercises the shared protocol over an actual WebSocket, -// using the production gateway, transport and dispatcher with a controlled adapter. -package contracttest - -import "github.com/MiniMax-AI/OpenAgentCore/internal/harnessconfig" - -import ( - "context" - "errors" - "net/http" - "net/http/httptest" - "strings" - "sync" - "sync/atomic" - "testing" - "time" - - "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/agent" - "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/dispatch" - "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/transport" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" -) - -const credential = "synthetic-contract-credential" - -type credentialStore struct{} - -func (credentialStore) GetDeviceCredential(context.Context, string) (device.Credential, bool, error) { - return device.Credential{ID: "runtime", WorkspaceID: "tenant", Type: gateway.RuntimeTypeAgentDaemon, CredentialHash: device.HashCredential(credential)}, true, nil -} - -func newGateway(t *testing.T) (*gateway.Registry, string) { - t.Helper() - reg := gateway.NewRegistry() - handler := gateway.NewHandler(gateway.HandlerConfig{Registry: reg, Authenticator: gateway.NewAuthenticator(credentialStore{})}) - server := httptest.NewServer(http.HandlerFunc(handler.WS)) - t.Cleanup(server.Close) - return reg, "ws" + strings.TrimPrefix(server.URL, "http") -} - -func dial(t *testing.T, endpoint, version string) (*transport.Conn, error) { - t.Helper() - ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) - defer cancel() - return transport.Dial(ctx, transport.DialOptions{WSURL: endpoint, DeviceID: "runtime", Credential: credential, DaemonVersion: version}) -} - -func TestWireContractRejectsVersionMismatchWithoutReconnect(t *testing.T) { - _, endpoint := newGateway(t) - for _, version := range []string{"0.7.0", "0.8.99", "0.8.", proto.Version + "-dev", proto.Version + "+build"} { - t.Run(version, func(t *testing.T) { - attempts := 0 - _, err := transport.Reconnect(t.Context(), func(context.Context) (*transport.Conn, error) { - attempts++ - return dial(t, endpoint, version) - }, transport.DefaultBackoff, nil) - if !errors.Is(err, transport.ErrIncompatibleVersion) || !errors.Is(err, transport.ErrPermanent) || attempts != 1 { - t.Fatalf("mismatch must stop after one attempt: attempts=%d error=%v", attempts, err) - } - }) - } -} - -type wireFixture struct { - core *gateway.Session - conn *transport.Conn - router *dispatch.Router - reg *gateway.Registry - endpoint string - stopped chan struct{} - shutdownErr error -} - -func connectFixture(t *testing.T, factory agent.ExecutorFactory) *wireFixture { - t.Helper() - reg, endpoint := newGateway(t) - conn, err := dial(t, endpoint, proto.Version) - if err != nil { - t.Fatal(err) - } - core, err := reg.WaitForDevice(t.Context(), "runtime", 3*time.Second) - if err != nil { - t.Fatal(err) - } - kinds := agent.NewRegistry() - kinds.RegisterKind(proto.SupportedAgentKind{Kind: "contract", Available: true, Capabilities: prototest.Capabilities(proto.AgentKindCapabilities{EnvironmentNone: proto.CapabilitySupported})}, - harnessconfig.Configuration{}, func(context.Context, proto.PromptRequestPayload, chan<- proto.Envelope) (agent.Session, error) { - return nil, errors.New("prepared execution must not use prompt_request") - }) - kinds.RegisterExecutor("contract", factory) - router, err := dispatch.New(dispatch.Config{Registry: kinds, Sender: conn}) - if err != nil { - t.Fatal(err) - } - f := &wireFixture{core: core, conn: conn, router: router, reg: reg, endpoint: endpoint, stopped: make(chan struct{})} - go func() { - for env := range conn.Recv() { - if err := router.Handle(t.Context(), env); err != nil { - t.Errorf("dispatch: %v", err) - } - } - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) - defer cancel() - f.shutdownErr = router.Shutdown(ctx) - close(f.stopped) - }() - t.Cleanup(func() { - conn.Close() - select { - case <-f.stopped: - if f.shutdownErr != nil { - t.Error(f.shutdownErr) - } - case <-time.After(4 * time.Second): - t.Error("Runtime shutdown did not complete") - } - core.Close("test finished") - }) - return f -} - -func (f *wireFixture) send(t *testing.T, kind, id string, payload any) { - t.Helper() - env, err := proto.NewEnvelope(kind, id, payload) - if err != nil { - t.Fatal(err) - } - ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) - defer cancel() - if err := f.core.Send(ctx, env); err != nil { - t.Fatal(err) - } -} - -func receive(t *testing.T, sub *gateway.Subscription) proto.Envelope { - t.Helper() - select { - case env, ok := <-sub.Events: - if !ok { - t.Fatalf("subscription closed: %v", sub.Err()) - } - return env - case <-time.After(3 * time.Second): - t.Fatal("no protocol response") - } - return proto.Envelope{} -} - -func status(t *testing.T, sub *gateway.Subscription, want string) proto.PreparationStatusPayload { - t.Helper() - for { - env := receive(t, sub) - var got proto.PreparationStatusPayload - if env.Type != proto.TypePreparationStatus || env.DecodePayload(&got) != nil { - t.Fatalf("invalid preparation response: %+v", env) - } - if got.State == want { - return got - } - if got.State != "preparing" && got.State != "starting" { - t.Fatalf("preparation state=%s, want=%s", got.State, want) - } - } -} - -func (f *wireFixture) prepare(t *testing.T) (*gateway.Subscription, proto.PreparationStatusPayload) { - t.Helper() - sub, err := f.core.SubscribePreparation("prepare") - if err != nil { - t.Fatal(err) - } - f.send(t, proto.TypeExecutionPrepare, "prepare", proto.ExecutionPreparePayload{ - SessionID: "session", Configuration: proto.PromptRequestPayload{AgentKind: "contract", AgentStateKey: "agents-api-session", StrictResume: true, DisableExecutionEnvironment: true}, - }) - return sub, status(t, sub, "ready") -} - -type controlledExecutor struct { - turn chan *controlledTurn - starts atomic.Int32 - closes atomic.Int32 -} - -func newExecutor() *controlledExecutor { - return &controlledExecutor{turn: make(chan *controlledTurn, 1)} -} -func (e *controlledExecutor) Close(context.Context) error { e.closes.Add(1); return nil } -func (e *controlledExecutor) StartTurn(_ context.Context, id string, _ proto.MessageInput, out chan<- proto.Envelope) (agent.Turn, error) { - e.starts.Add(1) - turn := &controlledTurn{id: id, out: out, cancelling: make(chan struct{}), allowCancel: make(chan struct{}), settled: make(chan struct{})} - e.turn <- turn - return turn, nil -} - -type controlledTurn struct { - id string - out chan<- proto.Envelope - cancelling, allowCancel, settled chan struct{} - cancelOnce, finishOnce sync.Once -} - -func (turn *controlledTurn) Cancel(ctx context.Context) error { - turn.cancelOnce.Do(func() { close(turn.cancelling) }) - select { - case <-turn.allowCancel: - turn.finishOnce.Do(func() { close(turn.out); close(turn.settled) }) - return nil - case <-ctx.Done(): - return ctx.Err() - } -} -func (turn *controlledTurn) CancellationOutcome() proto.DonePayload { - return proto.DonePayload{Content: "partial", Metadata: map[string]any{proto.DoneMetaAgentSessionID: "native-session"}} -} -func (turn *controlledTurn) AwaitSettlement(ctx context.Context) (agent.TurnSettlement, error) { - select { - case <-turn.settled: - return agent.TurnSettlement{Reason: "cancelled fixture"}, nil - case <-ctx.Done(): - return agent.TurnSettlement{}, ctx.Err() - } -} - -func TestWireContractCancellationWaitsForSettlement(t *testing.T) { - executor := newExecutor() - f := connectFixture(t, func(context.Context, proto.PromptRequestPayload) (agent.Executor, error) { return executor, nil }) - prepared, ready := f.prepare(t) - if executor.starts.Load() != 0 { - t.Fatal("preparation submitted input") - } - run, err := f.core.SubscribeDurable("run") - if err != nil { - t.Fatal(err) - } - f.send(t, proto.TypeExecutionStart, "prepare", proto.ExecutionStartPayload{ExecutorID: ready.ExecutorID, Handle: ready.Handle, RunID: "run", Input: proto.TextInput("hello")}) - started := status(t, prepared, "started") - if started.RunID != "run" || started.ExecutorID != ready.ExecutorID { - t.Fatal("start lost execution identity") - } - var turn *controlledTurn - select { - case turn = <-executor.turn: - case <-time.After(3 * time.Second): - t.Fatal("no native turn") - } - var unblock sync.Once - release := func() { unblock.Do(func() { close(turn.allowCancel) }) } - t.Cleanup(release) - result := make(chan proto.InteractionDecisionAckPayload, 1) - ackErr := make(chan error, 1) - go func() { - ctx, cancel := context.WithTimeout(t.Context(), 3*time.Second) - defer cancel() - env, _ := proto.NewEnvelope(proto.TypePromptCancel, "run", proto.PromptCancelPayload{DeliveryID: "cancel"}) - ack, err := f.core.SendAndWaitInteractionAck(ctx, env, "cancel") - result <- ack - ackErr <- err - }() - select { - case <-turn.cancelling: - case <-time.After(3 * time.Second): - t.Fatal("cancellation was not received") - } - select { - case <-result: - t.Fatal("receipt preceded native settlement") - default: - } - release() - select { - case ack := <-result: - if err := <-ackErr; err != nil || !ack.Applied || ack.Outcome == nil || ack.Outcome.Content != "partial" { - t.Fatalf("invalid cancellation receipt: %+v, %v", ack, err) - } - case <-time.After(3 * time.Second): - t.Fatal("missing settled cancellation receipt") - } - f.core.Unsubscribe("run") - for env := range run.Events { - if env.ID != "run" { - t.Fatal("settled cancellation output lost Run correlation") - } - } - if executor.starts.Load() != 1 { - t.Fatal("input was submitted more than once") - } -} - -func TestWireContractPreparationFailureCleansUpWithoutRunCompletion(t *testing.T) { - executor := newExecutor() - f := connectFixture(t, func(context.Context, proto.PromptRequestPayload) (agent.Executor, error) { - return executor, errors.New("native setup failed") - }) - sub, err := f.core.SubscribePreparation("prepare") - if err != nil { - t.Fatal(err) - } - run, err := f.core.SubscribeDurable("run") - if err != nil { - t.Fatal(err) - } - f.send(t, proto.TypeExecutionPrepare, "prepare", proto.ExecutionPreparePayload{SessionID: "session", Configuration: proto.PromptRequestPayload{AgentKind: "contract", AgentStateKey: "agents-api-session", StrictResume: true, DisableExecutionEnvironment: true}}) - failed := status(t, sub, "failed") - if failed.ErrorCode != "preparation_failed" || executor.starts.Load() != 0 || executor.closes.Load() != 1 { - t.Fatalf("failed preparation retained resources or started input: %+v starts=%d closes=%d", failed, executor.starts.Load(), executor.closes.Load()) - } - if len(run.Events) != 0 { - t.Fatal("preparation failure manufactured a Run result") - } -} - -func TestWireContractDisconnectIsUnknownAndReconnectDoesNotReplay(t *testing.T) { - executor := newExecutor() - f := connectFixture(t, func(context.Context, proto.PromptRequestPayload) (agent.Executor, error) { return executor, nil }) - prepared, ready := f.prepare(t) - run, err := f.core.SubscribeDurable("run") - if err != nil { - t.Fatal(err) - } - f.send(t, proto.TypeExecutionStart, "prepare", proto.ExecutionStartPayload{ExecutorID: ready.ExecutorID, Handle: ready.Handle, RunID: "run", Input: proto.TextInput("hello")}) - status(t, prepared, "started") - var turn *controlledTurn - select { - case turn = <-executor.turn: - case <-time.After(3 * time.Second): - t.Fatal("no native turn") - } - close(turn.allowCancel) - // Work has started. Losing observation cannot establish its result even - // when Runtime subsequently settles cleanup. - f.conn.Close() - select { - case <-f.core.Closed(): - case <-time.After(3 * time.Second): - t.Fatal("gateway stayed connected") - } - for env := range run.Events { - if env.Type == proto.TypeError || env.Type == proto.TypeDone { - t.Fatal("disconnect manufactured execution failure/completion") - } - } - if !errors.Is(run.Err(), gateway.ErrSessionClosed) { - t.Fatalf("disconnect outcome: %v", run.Err()) - } - conn, err := dial(t, f.endpoint, proto.Version) - if err != nil { - t.Fatal(err) - } - defer conn.Close() - core, err := f.reg.WaitForDevice(t.Context(), "runtime", 3*time.Second) - if err != nil { - t.Fatal(err) - } - defer core.Close("test done") - if core == f.core || f.reg.LookupRun("run") != nil { - t.Fatal("reconnect inherited stale Run ownership") - } - select { - case env := <-conn.Recv(): - t.Fatalf("reconnect replayed work for old handle %s: %+v", ready.Handle, env) - case <-time.After(30 * time.Millisecond): - } - select { - case <-f.stopped: - if f.shutdownErr != nil || executor.closes.Load() != 1 { - t.Fatalf("disconnect cleanup: %v, closes=%d", f.shutdownErr, executor.closes.Load()) - } - case <-time.After(3 * time.Second): - t.Fatal("disconnect cleanup did not settle") - } - if executor.starts.Load() != 1 { - t.Fatal("reconnect replayed input") - } -} - -// These fixtures exercise settlement only; active input is deliberately rejected. -func (*controlledTurn) SteerWithReceipt(context.Context, proto.PromptSteerPayload, func()) error { - return agent.ErrSteeringRejected -} diff --git a/docs/runtime-protocol.md b/docs/runtime-protocol.md index 1a7e1d4fc..ca03a782d 100644 --- a/docs/runtime-protocol.md +++ b/docs/runtime-protocol.md @@ -1,6 +1,6 @@ # Core–Runtime protocol -This protocol connects Core to a Runtime daemon after the daemon has its machine credential. It defines the meaning and order of the messages on the daemon connection. The wire types, limits and validators live once in [`internal/agentdaemon/proto`](../internal/agentdaemon/proto); Core's [gateway](../internal/agentdaemon/gateway) and the reference Runtime's [dispatcher](../apps/daemon/internal/dispatch) both use them, so there is no second payload schema to keep in sync. The HTTP routes that issue credentials and open the connection are in the [machine connection API](../contracts/agents-api/machine-api.md). +This protocol connects Core to a Runtime daemon after the daemon has its machine credential. It defines the meaning and order of the messages on the daemon connection. The wire types, limits and validators live once in [`internal/agentdaemon/proto`](../internal/agentdaemon/proto); Core's [gateway](../services/core/internal/runtimegateway) and the reference Runtime's [dispatcher](../apps/daemon/internal/dispatch) both use them, so there is no second payload schema to keep in sync. The HTTP routes that issue credentials and open the connection are in the [machine connection API](../contracts/agents-api/machine-api.md). Hosted and self-hosted Runtimes use the same protocol. A Harness joins through the [Harness adapter contract](../contracts/agents-api/harness-onboarding.md), which owns the Executor and Turn lifecycle obligations behind the Runtime registry. diff --git a/scripts/build-core.sh b/scripts/build-core.sh index 8785f80a3..60ee62a72 100755 --- a/scripts/build-core.sh +++ b/scripts/build-core.sh @@ -25,7 +25,7 @@ trap 'rm -rf "$build_context"' EXIT tar -C "$repo_root" -cf - \ go.mod go.sum \ contracts/agents-api/v1 \ - internal/agentdaemon/device internal/agentdaemon/gateway internal/agentdaemon/proto \ + internal/agentdaemon/proto \ internal/runtimefs internal/runtimebootstrap internal/agentnetwork internal/agentbundle internal/agentcapabilities internal/agentplugin internal/agentskill internal/harnessconfig internal/modelprovider internal/providerassets internal/obs/log services/core \ | tar -C "$build_context" -xf - diff --git a/scripts/name-allowlist.json b/scripts/name-allowlist.json index 20872f088..7db5451fd 100644 --- a/scripts/name-allowlist.json +++ b/scripts/name-allowlist.json @@ -249,11 +249,6 @@ "regex": "\"agents-api-\"", "reason": "AgentStateKey retains the existing daemon/native-session resume identity; capability snapshots bind to the Session UUID carried in that identity." }, - { - "path": "apps/daemon/internal/contracttest/wire_test.go", - "regex": "agents-api-session", - "reason": "The controlled Runtime fixture uses the existing Core Session state-key prefix required by execution admission." - }, { "path": "apps/daemon/internal/agent/mcode/tool_environment_test.go", "regex": "agents-api-", diff --git a/services/core/IMPLEMENTATION.md b/services/core/IMPLEMENTATION.md index b14d66664..24ea4bc2e 100644 --- a/services/core/IMPLEMENTATION.md +++ b/services/core/IMPLEMENTATION.md @@ -52,7 +52,7 @@ The Worker scans pending inputs with the same scheduling slots, Session locks, d ## Runtime connections -`internal/agentdaemon/gateway` is the shared daemon connection implementation; its persistence interfaces use `internal/agentdaemon/device`, and the frames and validators live in `internal/agentdaemon/proto`. It is a single-process registry: connectivity comes from the live registry, never a persisted online flag, and `last_seen_at` is diagnostic only. Session-to-device bindings are tenant-scoped and immutable. Revocation denies new connections and binding reads at once, and an open connection closes at its next heartbeat. +`services/core/internal/runtimegateway` is Core's daemon connection implementation; its persistence interfaces use `services/core/internal/runtimedevice`, and the frames and validators live in the shared `internal/agentdaemon/proto`. It is a single-process registry: connectivity comes from the live registry, never a persisted online flag, and `last_seen_at` is diagnostic only. Session-to-device bindings are tenant-scoped and immutable. Revocation denies new connections and binding reads at once, and an open connection closes at its next heartbeat. A dedicated self-hosted device is bound to exactly one Environment's Session and is excluded from general device selection, even within the tenant. Enrollment creates or recovers the device and binding atomically under the Session lock; the frozen workspace and capability directories come from the Session configuration and must match the local binding. Core rechecks the persisted Environment and device binding for preparation and active reads; capability discovery never selects or authorizes a device for this placement. diff --git a/services/core/cmd/device/main.go b/services/core/cmd/device/main.go index e66bd74ce..df1086680 100644 --- a/services/core/cmd/device/main.go +++ b/services/core/cmd/device/main.go @@ -15,9 +15,9 @@ import ( "github.com/jackc/pgx/v5/pgxpool" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/databaseurl" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -63,7 +63,7 @@ func run() error { return err } credential := base64.RawURLEncoding.EncodeToString(secret) - registered, err := s.CreateDevice(ctx, *tenant, *name, device.HashCredential(credential)) + registered, err := s.CreateDevice(ctx, *tenant, *name, runtimedevice.HashCredential(credential)) if err != nil { return err } diff --git a/services/core/cmd/server/core_metrics.go b/services/core/cmd/server/core_metrics.go index d169d1ef9..9c0147c39 100644 --- a/services/core/cmd/server/core_metrics.go +++ b/services/core/cmd/server/core_metrics.go @@ -4,9 +4,9 @@ import ( "context" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/coremetrics" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/jackc/pgx/v5/pgxpool" ) @@ -19,7 +19,7 @@ type coreMetricsSource struct { store *store.Store pool *pgxpool.Pool worker *execution.Worker - registry *gateway.Registry + registry *runtimegateway.Registry } func metricPtr[T any](value T) *T { return &value } diff --git a/services/core/cmd/server/daemon_bootstrap_test.go b/services/core/cmd/server/daemon_bootstrap_test.go index a96ff4e43..69880a323 100644 --- a/services/core/cmd/server/daemon_bootstrap_test.go +++ b/services/core/cmd/server/daemon_bootstrap_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" ) type bootstrapCredentialStore struct { @@ -17,17 +17,17 @@ type bootstrapCredentialStore struct { allocationID string } -func (s bootstrapCredentialStore) GetDeviceCredential(context.Context, string) (device.Credential, bool, error) { - return device.Credential{ID: "runtime", Type: gateway.RuntimeTypeAgentDaemon, - CredentialHash: device.HashCredential("synthetic-token"), RuntimeNodeID: s.nodeID, RuntimeAllocationID: s.allocationID}, true, nil +func (s bootstrapCredentialStore) GetDeviceCredential(context.Context, string) (runtimedevice.Credential, bool, error) { + return runtimedevice.Credential{ID: "runtime", Type: runtimegateway.RuntimeTypeAgentDaemon, + CredentialHash: runtimedevice.HashCredential("synthetic-token"), RuntimeNodeID: s.nodeID, RuntimeAllocationID: s.allocationID}, true, nil } func TestBootstrapAddressUsesPublicOrigin(t *testing.T) { const publicURL = "wss://public.example/api/v1/agent-daemon/ws" for _, node := range []string{"local-node", "remote-node", ""} { t.Run(node, func(t *testing.T) { - h := gateway.NewHandler(gateway.HandlerConfig{Registry: gateway.NewRegistry(), PublicWSURL: publicURL, - Authenticator: gateway.NewAuthenticator(bootstrapCredentialStore{nodeID: node})}) + h := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Registry: runtimegateway.NewRegistry(), PublicWSURL: publicURL, + Authenticator: runtimegateway.NewAuthenticator(bootstrapCredentialStore{nodeID: node})}) request := httptest.NewRequest(http.MethodPost, "https://forged.example/api/v1/agent-daemon/bootstrap", strings.NewReader(`{"device_id":"runtime","node_id":"local-node","runtime_node_id":"local-node"}`)) request.Header.Set("Authorization", "Bearer synthetic-token") diff --git a/services/core/cmd/server/http_routes_test.go b/services/core/cmd/server/http_routes_test.go index d231de3da..8bc464d58 100644 --- a/services/core/cmd/server/http_routes_test.go +++ b/services/core/cmd/server/http_routes_test.go @@ -14,8 +14,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -79,11 +79,11 @@ func (trapKeys) ResolveProjectAPIKey(context.Context, string) (store.ProjectAPIK func daemonComposition(t testing.TB) http.Handler { t.Helper() auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "org", ProjectID: "project", SubjectKind: "service_account", - SubjectID: "runner", TokenSHA256: device.HashCredential("project-key"), TenantID: uuid.NewString()}}) + SubjectID: "runner", TokenSHA256: runtimedevice.HashCredential("project-key"), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential("admin-key")}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin-key")}) if err != nil { t.Fatal(err) } diff --git a/services/core/cmd/server/main.go b/services/core/cmd/server/main.go index 3f65cac32..06618e47f 100644 --- a/services/core/cmd/server/main.go +++ b/services/core/cmd/server/main.go @@ -31,7 +31,6 @@ import ( "syscall" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/coremetrics" @@ -41,6 +40,7 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/providercontract" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimeenrollment" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimehistory" historystoreresolver "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimehistory/storeresolver" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimeobs" @@ -221,7 +221,7 @@ func run() error { options = append(options, api.WithRuntimeHistory(historyService)) } var daemonHandler http.Handler - var registry *gateway.Registry + var registry *runtimegateway.Registry if public != "" { wsURL, err := runtimeWebSocketURL(public) if err != nil { diff --git a/services/core/internal/api/admin_resources_test.go b/services/core/internal/api/admin_resources_test.go index 2f22e6441..365ceac94 100644 --- a/services/core/internal/api/admin_resources_test.go +++ b/services/core/internal/api/admin_resources_test.go @@ -8,9 +8,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -46,7 +46,7 @@ func adminTestHandler(t *testing.T, options ...Option) (http.Handler, *recording if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) if err != nil { t.Fatal(err) } @@ -84,7 +84,7 @@ func TestAdminResourcesHaveExplicitTargetWithoutCallerImpersonation(t *testing.T if err != nil { t.Fatal(err) } - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) resources := &adminReadFixture{} h, err := NewHandler(resources, auth, "codex", WithProjectAPIKeys(managementProjectStore(key), admin)) if err != nil { @@ -148,7 +148,7 @@ func (s *summaryFixture) ReadAdminSummary(_ context.Context, tenant string, filt func TestAdminSummaryUsesPublicStateAndNullUsageCoverage(t *testing.T) { key := callerBinding() auth, _ := NewAuthenticator([]APIKey{key}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) fixture := &summaryFixture{} h, err := NewHandler(&recordingStore{}, auth, "codex", WithProjectAPIKeys(managementProjectStore(key), admin), WithAdminManagement(fixture)) if err != nil { diff --git a/services/core/internal/api/admin_runtime_test.go b/services/core/internal/api/admin_runtime_test.go index a0678aa8c..8c1e0e7a1 100644 --- a/services/core/internal/api/admin_runtime_test.go +++ b/services/core/internal/api/admin_runtime_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimeobs" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -48,7 +48,7 @@ func adminRuntimeFixture(t *testing.T, projects []store.Project, targets []store if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/admin_session_archive_test.go b/services/core/internal/api/admin_session_archive_test.go index 5abf5460b..b96c3286a 100644 --- a/services/core/internal/api/admin_session_archive_test.go +++ b/services/core/internal/api/admin_session_archive_test.go @@ -6,8 +6,8 @@ import ( "net/http" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -38,7 +38,7 @@ func (s *archiveManagementFixture) GetManagedSessionArchive(_ context.Context, t func TestAdminSessionArchiveAuthorityAndValidation(t *testing.T) { key := callerBinding() auth, _ := NewAuthenticator([]APIKey{key}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) fixture := &archiveManagementFixture{} h, err := NewHandler(&recordingStore{}, auth, "codex", WithProjectAPIKeys(managementProjectStore(key), admin), WithAdminManagement(fixture), WithSessionArchive(fixture.ArchiveManagedSession)) if err != nil { diff --git a/services/core/internal/api/auth_test.go b/services/core/internal/api/auth_test.go index aacb81ffb..a99b42a04 100644 --- a/services/core/internal/api/auth_test.go +++ b/services/core/internal/api/auth_test.go @@ -5,13 +5,13 @@ import ( "net/http/httptest" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) func callerBinding() APIKey { - return APIKey{TokenSHA256: device.HashCredential("caller"), TenantID: uuid.NewString(), + return APIKey{TokenSHA256: runtimedevice.HashCredential("caller"), TenantID: uuid.NewString(), OrganizationID: "org-one", ProjectID: "project-one", SubjectKind: "user", SubjectID: "user-one"} } @@ -24,8 +24,8 @@ func TestAuthenticatorRequiresDatabaseResolver(t *testing.T) { func TestCallerPrincipalHeadersAndKeyRotation(t *testing.T) { key := callerBinding() rotated, peer := key, key - rotated.TokenSHA256 = device.HashCredential("rotated") - peer.TokenSHA256 = device.HashCredential("peer") + rotated.TokenSHA256 = runtimedevice.HashCredential("rotated") + peer.TokenSHA256 = runtimedevice.HashCredential("peer") auth, err := NewAuthenticator([]APIKey{key, rotated, peer}) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/contract_routes_test.go b/services/core/internal/api/contract_routes_test.go index 58b38439e..e0d68b6c5 100644 --- a/services/core/internal/api/contract_routes_test.go +++ b/services/core/internal/api/contract_routes_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/nativeinstaller" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/go-chi/chi/v5" "gopkg.in/yaml.v3" @@ -60,7 +60,7 @@ func contractOperations(t *testing.T, file, prefix string) map[string]bool { // The pinned upstream /v1 set is checked by TestEveryRouteAuthenticatesItsCanonicalPath // and the contract tests. func TestContractsPublishExactlyTheRegisteredCoreAndMachineRoutes(t *testing.T) { - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential(routingAdminKey)}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(routingAdminKey)}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/core_errors_test.go b/services/core/internal/api/core_errors_test.go index 2cd898618..e2b680d8d 100644 --- a/services/core/internal/api/core_errors_test.go +++ b/services/core/internal/api/core_errors_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/go-chi/chi/v5" ) @@ -21,7 +21,7 @@ func TestCoreErrorDetailsAreScopedByRouterNotRequestPath(t *testing.T) { }, "expected_generation") }) router := chi.NewRouter() - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/core_metrics_test.go b/services/core/internal/api/core_metrics_test.go index 1685fb4a3..5cafee982 100644 --- a/services/core/internal/api/core_metrics_test.go +++ b/services/core/internal/api/core_metrics_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/coremetrics" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) type metricsFixture struct { @@ -27,7 +27,7 @@ func (f *metricsFixture) RecordUnavailable() { f.refusals++ } func TestCoreMetricsAdministratorContract(t *testing.T) { key := callerBinding() auth, _ := NewAuthenticator([]APIKey{key}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) f := &metricsFixture{} h, err := NewHandler(&recordingStore{}, auth, "codex", WithProjectAPIKeys(managementProjectStore(key), admin), WithCoreMetrics(f)) if err != nil { diff --git a/services/core/internal/api/core_store_validation_test.go b/services/core/internal/api/core_store_validation_test.go index 1cf4ad1d7..443cb3ebf 100644 --- a/services/core/internal/api/core_store_validation_test.go +++ b/services/core/internal/api/core_store_validation_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -73,7 +73,7 @@ func TestCoreStoreValidationFieldsAndPublicFallback(t *testing.T) { func TestCoreActiveCapacityUpperBoundNamesSubmittedField(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) h, err := NewHandler(&recordingStore{}, project, "codex", WithSandboxManager(&store.Store{}, admin)) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/environment_creation_test.go b/services/core/internal/api/environment_creation_test.go index 422d45abf..ca72dd392 100644 --- a/services/core/internal/api/environment_creation_test.go +++ b/services/core/internal/api/environment_creation_test.go @@ -12,8 +12,8 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -54,7 +54,7 @@ func environmentCreationHandler(t *testing.T, engine string, options ...Option) fixture := &environmentCreationFixture{} auth, err := NewAuthenticator([]APIKey{{ OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", - TokenSHA256: device.HashCredential("key"), TenantID: uuid.NewString(), + TokenSHA256: runtimedevice.HashCredential("key"), TenantID: uuid.NewString(), }}) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/environment_executor_management_test.go b/services/core/internal/api/environment_executor_management_test.go index 16f7bb7bd..e16db934c 100644 --- a/services/core/internal/api/environment_executor_management_test.go +++ b/services/core/internal/api/environment_executor_management_test.go @@ -8,9 +8,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -56,7 +56,7 @@ func TestProjectExecutorCredentialsHTTP(t *testing.T) { if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) if err != nil { t.Fatal(err) } @@ -158,7 +158,7 @@ func TestExecutorConnectionListObservation(t *testing.T) { bound := "bound-key" f := &executorManagementFixture{connection: store.ExecutorConnectionState{DeviceID: "device", BoundKeyID: &bound, EnrolledAt: &at, CredentialHash: "private-digest", EnvironmentStatus: "connected"}} auth, _ := NewAuthenticator([]APIKey{key}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) opts := []Option{WithProjectAPIKeys(managementProjectStore(key), admin)} if tc.observer { opts = append(opts, WithExecutorConnections(func(_ context.Context, environment, digest string) (bool, error) { @@ -197,7 +197,7 @@ func TestExecutorConnectionListUsesResolvedEnvironment(t *testing.T) { connection: store.ExecutorConnectionState{DeviceID: "device", CredentialHash: "private-digest", EnvironmentStatus: "connected"}, } auth, _ := NewAuthenticator([]APIKey{key}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) observations := 0 h, err := NewHandler(f, auth, "codex", WithProjectAPIKeys(managementProjectStore(key), admin), WithExecutorConnections(func(_ context.Context, environment, digest string) (bool, error) { diff --git a/services/core/internal/api/environment_files_create_test.go b/services/core/internal/api/environment_files_create_test.go index 9b0010585..b3e963bd4 100644 --- a/services/core/internal/api/environment_files_create_test.go +++ b/services/core/internal/api/environment_files_create_test.go @@ -11,8 +11,8 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -41,8 +41,8 @@ func environmentFileCreateHandler(t *testing.T, extra ...Option) (http.Handler, base.environment.Configuration = json.RawMessage(`{"type":"openai_hosted","network":{"access":"disabled"}}`) f := &environmentFileCreateFixture{environmentFilesFixture: base} auth, err := NewAuthenticator([]APIKey{ - {OrganizationID: "org", ProjectID: "project", SubjectKind: "user", SubjectID: "caller", TokenSHA256: device.HashCredential("files-key"), TenantID: f.environment.TenantID}, - {OrganizationID: "org", ProjectID: "other", SubjectKind: "user", SubjectID: "other", TokenSHA256: device.HashCredential("other-key"), TenantID: uuid.NewString()}, + {OrganizationID: "org", ProjectID: "project", SubjectKind: "user", SubjectID: "caller", TokenSHA256: runtimedevice.HashCredential("files-key"), TenantID: f.environment.TenantID}, + {OrganizationID: "org", ProjectID: "other", SubjectKind: "user", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential("other-key"), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/environment_files_test.go b/services/core/internal/api/environment_files_test.go index 8eda51ac9..93b29e544 100644 --- a/services/core/internal/api/environment_files_test.go +++ b/services/core/internal/api/environment_files_test.go @@ -13,9 +13,9 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -69,7 +69,7 @@ func environmentFilesHandler(t *testing.T, enabled bool) (http.Handler, *environ {"other-key", uuid.NewString(), "other-project"}, } { keys = append(keys, APIKey{OrganizationID: "files-org", ProjectID: key.project, SubjectKind: "user", SubjectID: key.project, - TokenSHA256: device.HashCredential(key.token), TenantID: key.tenant}) + TokenSHA256: runtimedevice.HashCredential(key.token), TenantID: key.tenant}) } auth, err := NewAuthenticator(keys) if err != nil { diff --git a/services/core/internal/api/environment_installation_test.go b/services/core/internal/api/environment_installation_test.go index f3c77d4bd..9196eb64c 100644 --- a/services/core/internal/api/environment_installation_test.go +++ b/services/core/internal/api/environment_installation_test.go @@ -9,9 +9,9 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/nativeinstaller" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -37,7 +37,7 @@ func (f *installationFixture) ClaimEnvironmentInstallation(context.Context, stri func TestSelfHostedCreationReturnsInstallationWithoutWebCredential(t *testing.T) { f := &installationFixture{} - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential("project-key"), TenantID: uuid.NewString()}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential("project-key"), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/environments_test.go b/services/core/internal/api/environments_test.go index 13744ef1f..c8260b9d7 100644 --- a/services/core/internal/api/environments_test.go +++ b/services/core/internal/api/environments_test.go @@ -10,7 +10,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -37,7 +37,7 @@ func environmentResourceHandler(t *testing.T) (http.Handler, *environmentResourc }} auth, err := NewAuthenticator([]APIKey{{ OrganizationID: "resource-org", ProjectID: "resource-project", SubjectKind: "user", SubjectID: "resource-reader", - TokenSHA256: device.HashCredential("resource-key"), TenantID: f.environment.TenantID, + TokenSHA256: runtimedevice.HashCredential("resource-key"), TenantID: f.environment.TenantID, }}) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/hosted_failure_test.go b/services/core/internal/api/hosted_failure_test.go index 4549b1c84..6929698df 100644 --- a/services/core/internal/api/hosted_failure_test.go +++ b/services/core/internal/api/hosted_failure_test.go @@ -14,7 +14,7 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -107,7 +107,7 @@ func TestGetStreamEndsAfterHostedProvisioningFailure(t *testing.T) { f := &streamFixture{session: hostedFailureSession()} f.session.TenantID = uuid.NewString() f.session.Environment.TenantID = f.session.TenantID - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential("key"), TenantID: f.session.TenantID}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential("key"), TenantID: f.session.TenantID}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/installation_test.go b/services/core/internal/api/installation_test.go index 9be24380f..24a7f9778 100644 --- a/services/core/internal/api/installation_test.go +++ b/services/core/internal/api/installation_test.go @@ -8,13 +8,13 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) func TestInstallationReadNeedsOnlyTheCoreKey(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) public, id := "https://core.example", "5b7c0f3e-0000-4000-8000-000000000001" settings, err := ParseInstallationConfiguration([]byte(`{"path":"/home/alice/.oac/core/config.json","apply_command":"/home/alice/.oac/core/oac apply", "applied_at":"2026-09-25T09:30:00Z","settings":[{"key":"ports.core","value":8091,"default":8091,"changeable":true,"sensitive":false,"restarts":["core"]}, @@ -65,7 +65,7 @@ func TestInstallationSnapshotCannotCarryASensitiveValue(t *testing.T) { func TestDeploymentAddressIsNotInput(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) initializations := 0 initialize := func(_ context.Context, input store.SandboxDeploymentSetupRequest) (store.RuntimeDeploymentView, error) { initializations++ diff --git a/services/core/internal/api/project_api_keys_test.go b/services/core/internal/api/project_api_keys_test.go index 73f285eb6..ff264afc3 100644 --- a/services/core/internal/api/project_api_keys_test.go +++ b/services/core/internal/api/project_api_keys_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -32,7 +32,7 @@ func (s *projectKeyStoreFixture) ResolveProjectAPIKey(_ context.Context, digest if s.resolve != nil { return store.ProjectAPIKeyBinding{}, s.resolve } - if digest != device.HashCredential("issued-project-key") { + if digest != runtimedevice.HashCredential("issued-project-key") { return store.ProjectAPIKeyBinding{}, store.ErrNotFound } return s.binding, nil @@ -103,7 +103,7 @@ func TestAdministratorCredentialSeparation(t *testing.T) { if err := ValidateCredentialSeparation(t.Context(), nil, s); err == nil { t.Fatal("missing administrator accepted") } - digest := device.HashCredential("admin") + digest := runtimedevice.HashCredential("admin") admin, _ := NewDeploymentAuthenticator([]string{digest}) if err := ValidateCredentialSeparation(t.Context(), admin, s); err != nil || len(s.digests) != 1 || s.digests[0] != digest { t.Fatal("administrator digest was not checked against persisted keys", err) diff --git a/services/core/internal/api/resource_query_test.go b/services/core/internal/api/resource_query_test.go index cec5331e0..fc61d3d2e 100644 --- a/services/core/internal/api/resource_query_test.go +++ b/services/core/internal/api/resource_query_test.go @@ -13,7 +13,7 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -72,8 +72,8 @@ func twoTenantHandler(t *testing.T, s ResourceStore, options ...Option) (http.Ha t.Helper() owner, foreign := uuid.NewString(), uuid.NewString() auth, err := NewAuthenticator([]APIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential("test-api-key"), TenantID: owner}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "foreign", TokenSHA256: device.HashCredential("foreign-key"), TenantID: foreign}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential("test-api-key"), TenantID: owner}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "foreign", TokenSHA256: runtimedevice.HashCredential("foreign-key"), TenantID: foreign}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/routing_test.go b/services/core/internal/api/routing_test.go index 06ae07c4f..90b948a84 100644 --- a/services/core/internal/api/routing_test.go +++ b/services/core/internal/api/routing_test.go @@ -18,9 +18,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/go-chi/chi/v5" "github.com/google/uuid" @@ -82,7 +82,7 @@ type routingKeys struct { } func (k routingKeys) ResolveProjectAPIKey(_ context.Context, digest string) (store.ProjectAPIKeyBinding, error) { - if digest != device.HashCredential(routingDerivedKey) { + if digest != runtimedevice.HashCredential(routingDerivedKey) { return store.ProjectAPIKeyBinding{}, store.ErrNotFound } return store.ProjectAPIKeyBinding{Principal: k.principal}, nil @@ -102,21 +102,21 @@ func (missingFiles) GetSourceFile(context.Context, string, string) (store.Source func routingFixture(t *testing.T) (http.Handler, *chi.Mux, *routingStore) { t.Helper() tenant := uuid.NewString() - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: "test-project", SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(routingKey), TenantID: tenant}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: "test-project", SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(routingKey), TenantID: tenant}}) if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential(routingAdminKey)}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(routingAdminKey)}) if err != nil { t.Fatal(err) } s := &routingStore{tenant: tenant, agent: store.SavedAgent{ID: uuid.NewString(), TenantID: tenant, Metadata: map[string]string{}, Configuration: json.RawMessage(`{"model":"fixture"}`), CreatedAt: time.Unix(1700000000, 0), UpdatedAt: time.Unix(1700000000, 0)}} - binding, err := auth.keys.ResolveProjectAPIKey(t.Context(), device.HashCredential(routingKey)) + binding, err := auth.keys.ResolveProjectAPIKey(t.Context(), runtimedevice.HashCredential(routingKey)) if err != nil { t.Fatal(err) } - auth.keys.(fixtureKeyResolver)[device.HashCredential(routingDerivedKey)] = binding + auth.keys.(fixtureKeyResolver)[runtimedevice.HashCredential(routingDerivedKey)] = binding options := []Option{WithSandboxManager(&store.Store{}, admin), WithProjectAPIKeys(routingKeys{principal: binding.Principal}, admin), WithSourceFiles(missingFiles{})} handler, err := NewHandler(s, auth, "codex", options...) if err != nil { @@ -393,10 +393,10 @@ func TestEveryRouteAuthenticatesItsCanonicalPath(t *testing.T) { {"/core/v1/sandbox/%2E%2E/%2E%2E/%2E%2E/v1/agents", withHeaders([]string{"Authorization", "Bearer " + routingAdminKey}, beta), http.StatusUnauthorized, ""}, {"/core/v1/sandbox/nodes%2F..%2F..%2F..%2Fv1%2Fagents", withHeaders([]string{"Authorization", "Bearer " + routingAdminKey}, beta), http.StatusNotFound, ""}, // Project API key management keeps deployment administrator authority. - {"/v1/%2E%2E/core/v1/projects/" + device.HashCredential(routingKey), withHeaders(project, beta), http.StatusUnauthorized, "invalid_admin_key"}, - {"/v1/agents//../../core/v1/projects/" + device.HashCredential(routingKey), withHeaders([]string{"Authorization", "Bearer " + routingDerivedKey}, beta), http.StatusUnauthorized, "invalid_admin_key"}, - {"/v1/x{/..%2F..%2Fcore/v1/project-api-keys/" + device.HashCredential(routingKey), http.Header{}, http.StatusBadRequest, "invalid_beta"}, - {"/core/v1/projects/" + device.HashCredential(routingKey) + "/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/v1/agents", withHeaders([]string{"Authorization", "Bearer " + routingAdminKey}, beta), http.StatusUnauthorized, ""}, + {"/v1/%2E%2E/core/v1/projects/" + runtimedevice.HashCredential(routingKey), withHeaders(project, beta), http.StatusUnauthorized, "invalid_admin_key"}, + {"/v1/agents//../../core/v1/projects/" + runtimedevice.HashCredential(routingKey), withHeaders([]string{"Authorization", "Bearer " + routingDerivedKey}, beta), http.StatusUnauthorized, "invalid_admin_key"}, + {"/v1/x{/..%2F..%2Fcore/v1/project-api-keys/" + runtimedevice.HashCredential(routingKey), http.Header{}, http.StatusBadRequest, "invalid_beta"}, + {"/core/v1/projects/" + runtimedevice.HashCredential(routingKey) + "/%2E%2E/%2E%2E/%2E%2E/%2E%2E/%2E%2E/v1/agents", withHeaders([]string{"Authorization", "Bearer " + routingAdminKey}, beta), http.StatusUnauthorized, ""}, } { got := serve(handler, http.MethodGet, test.target, "", test.header) if got.Code != test.status || (test.code != "" && !strings.Contains(got.Body.String(), `"code":"`+test.code+`"`)) { diff --git a/services/core/internal/api/sandbox_configuration_discovery_test.go b/services/core/internal/api/sandbox_configuration_discovery_test.go index 12e0510d6..96269f057 100644 --- a/services/core/internal/api/sandbox_configuration_discovery_test.go +++ b/services/core/internal/api/sandbox_configuration_discovery_test.go @@ -8,14 +8,14 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) func TestSandboxE2BDiscoveryAuthenticationAndCredentialPrivacy(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) calls := 0 discover := func(ctx context.Context, kind string, input sandbox.ConfigurationDiscoveryInput) (json.RawMessage, error) { calls++ diff --git a/services/core/internal/api/sandbox_deployment_changes_test.go b/services/core/internal/api/sandbox_deployment_changes_test.go index e270e7a9a..fb5fe1e18 100644 --- a/services/core/internal/api/sandbox_deployment_changes_test.go +++ b/services/core/internal/api/sandbox_deployment_changes_test.go @@ -9,13 +9,13 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) func TestSandboxDeploymentChangesAuthenticateAndDecode(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) updates, resets := 0, 0 update := func(_ context.Context, in store.SandboxDeploymentUpdateRequest) (store.RuntimeDeploymentView, error) { updates++ diff --git a/services/core/internal/api/sandbox_deployment_setup_test.go b/services/core/internal/api/sandbox_deployment_setup_test.go index cf43aa16c..21656b76b 100644 --- a/services/core/internal/api/sandbox_deployment_setup_test.go +++ b/services/core/internal/api/sandbox_deployment_setup_test.go @@ -7,13 +7,13 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) func TestSandboxDeploymentSetupRequiresAdministratorAndStrictBody(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) calls := 0 initialize := func(_ context.Context, input store.SandboxDeploymentSetupRequest) (store.RuntimeDeploymentView, error) { calls++ diff --git a/services/core/internal/api/sandbox_manager_test.go b/services/core/internal/api/sandbox_manager_test.go index e28c4b65d..bc9cfd042 100644 --- a/services/core/internal/api/sandbox_manager_test.go +++ b/services/core/internal/api/sandbox_manager_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -15,7 +15,7 @@ func TestSandboxAdministratorIsSeparateFromProject(t *testing.T) { if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) if err != nil { t.Fatal(err) } @@ -43,7 +43,7 @@ func TestSandboxAdministratorIsSeparateFromProject(t *testing.T) { if result.Code != http.StatusUnauthorized { t.Fatal("admin key gained project authority", result.Code) } - reused, _ := NewDeploymentAuthenticator([]string{device.HashCredential("caller")}) + reused, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("caller")}) collided, err := NewHandler(&recordingStore{}, project, "codex", WithSandboxManager(&store.Store{}, reused)) if err != nil { t.Fatal(err) @@ -56,7 +56,7 @@ func TestSandboxAdministratorIsSeparateFromProject(t *testing.T) { } } func TestSandboxEnrollmentDoesNotAcceptProjectAsAdmin(t *testing.T) { - auth, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + auth, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) called := false protected := auth.authenticate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true; w.WriteHeader(http.StatusNoContent) })) for _, token := range []string{"caller", "node-credential", "enrollment-token", ""} { @@ -81,7 +81,7 @@ func TestSandboxLocalNodeRemovalExplainsDeploymentBinding(t *testing.T) { func TestSandboxEnrollmentCapacityIsAdministratorOnly(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) h, err := NewHandler(&recordingStore{}, project, "codex", WithSandboxManager(&store.Store{}, admin)) if err != nil { t.Fatal(err) @@ -115,7 +115,7 @@ func TestSandboxEnrollmentCapacityIsAdministratorOnly(t *testing.T) { // before any token is read. func TestSandboxNodeEnrollmentRequiresCoreURL(t *testing.T) { project, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) h, err := NewHandler(&recordingStore{}, project, "codex", WithSandboxManager(&store.Store{}, admin)) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/sandbox_node_detail_test.go b/services/core/internal/api/sandbox_node_detail_test.go index f19402477..5722b3423 100644 --- a/services/core/internal/api/sandbox_node_detail_test.go +++ b/services/core/internal/api/sandbox_node_detail_test.go @@ -1,14 +1,14 @@ package api import ( - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "testing" ) func TestSandboxNodeDetailValidationAndAuthentication(t *testing.T) { auth, _ := NewAuthenticator([]APIKey{callerBinding()}) - admin, _ := NewDeploymentAuthenticator([]string{device.HashCredential("administrator")}) + admin, _ := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("administrator")}) h, err := NewHandler(&recordingStore{}, auth, "codex", WithSandboxManager(&store.Store{}, admin)) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/session_creation_stream_test.go b/services/core/internal/api/session_creation_stream_test.go index b5f9d9d29..f0290f9fe 100644 --- a/services/core/internal/api/session_creation_stream_test.go +++ b/services/core/internal/api/session_creation_stream_test.go @@ -14,8 +14,8 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -141,7 +141,7 @@ func newCreationStreamHarness(t *testing.T) *creationStreamHarness { }}} auth, err := NewAuthenticator([]APIKey{{ OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", - TokenSHA256: device.HashCredential("key"), TenantID: tenant, + TokenSHA256: runtimedevice.HashCredential("key"), TenantID: tenant, }}) if err != nil { t.Fatal(err) @@ -708,7 +708,7 @@ func (a *countingStreamAdmission) CreateSessionStream(context.Context, string, s } func TestCreationStreamCapabilityIsCheckedBeforeCreation(t *testing.T) { - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential("key"), TenantID: uuid.NewString()}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential("key"), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/session_environment_http_test.go b/services/core/internal/api/session_environment_http_test.go index 44f064679..3d0cdec8e 100644 --- a/services/core/internal/api/session_environment_http_test.go +++ b/services/core/internal/api/session_environment_http_test.go @@ -11,7 +11,7 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -44,7 +44,7 @@ func TestSelfHostedSessionHTTPReadListMetadataAndLiveStream(t *testing.T) { }}}} auth, err := NewAuthenticator([]APIKey{{ OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", - TokenSHA256: device.HashCredential("key"), TenantID: session.TenantID, + TokenSHA256: runtimedevice.HashCredential("key"), TenantID: session.TenantID, }}) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/stream_authority_test.go b/services/core/internal/api/stream_authority_test.go index 9d2608321..19d585ef1 100644 --- a/services/core/internal/api/stream_authority_test.go +++ b/services/core/internal/api/stream_authority_test.go @@ -12,7 +12,7 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -46,7 +46,7 @@ func (s *busyAuthorityStream) ListSessionEvents(ctx context.Context, _, _ string func TestBusyStreamRechecksAuthorityAndFailsClosed(t *testing.T) { key := callerBinding() - key.TokenSHA256 = device.HashCredential("stream") + key.TokenSHA256 = runtimedevice.HashCredential("stream") auth, err := NewAuthenticator([]APIKey{key}) if err != nil { t.Fatal(err) diff --git a/services/core/internal/api/stream_test.go b/services/core/internal/api/stream_test.go index 95b6a4d97..95e7bc174 100644 --- a/services/core/internal/api/stream_test.go +++ b/services/core/internal/api/stream_test.go @@ -13,7 +13,7 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -62,7 +62,7 @@ func (f *streamFixture) ListSessionEvents(_ context.Context, _, _ string, cursor func TestLiveStreamAuthDisconnectRecoveryAndServerDeadline(t *testing.T) { f := &streamFixture{session: store.Session{ID: uuid.NewString(), TenantID: uuid.NewString(), CreatedAt: time.Now(), Metadata: map[string]string{}, Configuration: json.RawMessage(`{"agent":{"id":"agent_test","model":"model","tools":[]},"environment":{"type":"none"}}`)}} - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential("key"), TenantID: f.session.TenantID}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential("foreign"), TenantID: uuid.NewString()}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential("key"), TenantID: f.session.TenantID}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential("foreign"), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/vaults_test.go b/services/core/internal/api/vaults_test.go index 94ebdd5d5..815915e4d 100644 --- a/services/core/internal/api/vaults_test.go +++ b/services/core/internal/api/vaults_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -47,7 +47,7 @@ func (f *vaultResourceFixture) UpdateAgent(context.Context, string, string, stor func vaultResourceHandler(t *testing.T) (http.Handler, *vaultResourceFixture) { t.Helper() f := &vaultResourceFixture{vault: store.Vault{ID: uuid.NewString(), TenantID: uuid.NewString(), Metadata: map[string]string{}, CreatedAt: time.Unix(1700000000, 0)}} - auth, err := NewAuthenticator([]APIKey{{OrganizationID: "vault-org", ProjectID: "vault-project", SubjectKind: "user", SubjectID: "vault-owner", TokenSHA256: device.HashCredential("vault-key"), TenantID: f.vault.TenantID}}) + auth, err := NewAuthenticator([]APIKey{{OrganizationID: "vault-org", ProjectID: "vault-project", SubjectKind: "user", SubjectID: "vault-owner", TokenSHA256: runtimedevice.HashCredential("vault-key"), TenantID: f.vault.TenantID}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/api/write_audit_test.go b/services/core/internal/api/write_audit_test.go index 1e55dbd35..cb73c24cb 100644 --- a/services/core/internal/api/write_audit_test.go +++ b/services/core/internal/api/write_audit_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/writeaudit" "github.com/google/uuid" @@ -47,7 +47,7 @@ func TestWriteAuditQueriesDeploymentScopeAndValidation(t *testing.T) { if err != nil { t.Fatal(err) } - admin, err := NewDeploymentAuthenticator([]string{device.HashCredential("admin")}) + admin, err := NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("admin")}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/archive_cancellation_cleanup_test.go b/services/core/internal/execution/archive_cancellation_cleanup_test.go index e7bd7c329..d1412a553 100644 --- a/services/core/internal/execution/archive_cancellation_cleanup_test.go +++ b/services/core/internal/execution/archive_cancellation_cleanup_test.go @@ -14,12 +14,12 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/microsandbox" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" - runtimegateway "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -85,7 +85,7 @@ func TestArchiveWaitingCleanupReceiptBarrier(t *testing.T) { t.Fatal(err) } secret := uuid.NewString() - owner, err := writer.ReserveRuntimeAllocation(t.Context(), project.TenantID, session.Environment.ID, installation, device.HashCredential(secret)) + owner, err := writer.ReserveRuntimeAllocation(t.Context(), project.TenantID, session.Environment.ID, installation, runtimedevice.HashCredential(secret)) if err != nil { t.Fatal(err) } @@ -112,18 +112,18 @@ func TestArchiveWaitingCleanupReceiptBarrier(t *testing.T) { t.Fatal(err) } } - registry := gateway.NewRegistry() + registry := runtimegateway.NewRegistry() if scenario.delivery { server := httptest.NewUnstartedServer(nil) wsURL := "ws://" + server.Listener.Addr().String() + "/api/v1/agent-daemon/ws" - handler, liveRegistry, err := runtimegateway.NewGateway(s, wsURL) + handler, liveRegistry, err := runtime.NewGateway(s, wsURL) if err != nil { t.Fatal(err) } registry = liveRegistry server.Config.Handler = handler server.Start() - t.Cleanup(func() { runtimegateway.CloseConnections(registry); server.Close() }) + t.Cleanup(func() { runtime.CloseConnections(registry); server.Close() }) u, _ := url.Parse(wsURL) u.RawQuery = url.Values{"device_id": {owner.DeviceID}, "version": {proto.Version}}.Encode() conn, _, err := websocket.DefaultDialer.Dial(u.String(), http.Header{"Authorization": {"Bearer " + secret}}) @@ -131,7 +131,7 @@ func TestArchiveWaitingCleanupReceiptBarrier(t *testing.T) { t.Fatal(err) } t.Cleanup(func() { conn.Close() }) - var peer *gateway.Session + var peer *runtimegateway.Session for end := time.Now().Add(3 * time.Second); ; { peer, err = registry.LookupDevice(owner.DeviceID) if err == nil { diff --git a/services/core/internal/execution/artifacts.go b/services/core/internal/execution/artifacts.go index 1ff9cacad..3ed933b3b 100644 --- a/services/core/internal/execution/artifacts.go +++ b/services/core/internal/execution/artifacts.go @@ -6,12 +6,12 @@ import ( "io" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) -func (d *Dispatcher) captureCompletedArtifacts(ctx context.Context, peer *gateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, turnID string, result Result, status string) (Result, string) { +func (d *Dispatcher) captureCompletedArtifacts(ctx context.Context, peer *runtimegateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, turnID string, result Result, status string) (Result, string) { if status != store.TurnCompleted || !LocalWorkspaceConfiguration(environment.Configuration) { return result, status } diff --git a/services/core/internal/execution/delivery.go b/services/core/internal/execution/delivery.go index c95768983..b215a7d2e 100644 --- a/services/core/internal/execution/delivery.go +++ b/services/core/internal/execution/delivery.go @@ -7,8 +7,8 @@ import ( "strconv" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -25,7 +25,7 @@ type cancellationResult struct { err error } -func requestCancellation(ctx context.Context, peer *gateway.Session, runID string) <-chan cancellationResult { +func requestCancellation(ctx context.Context, peer *runtimegateway.Session, runID string) <-chan cancellationResult { out := make(chan cancellationResult, 1) go func() { id := "cancel:" + runID @@ -36,7 +36,7 @@ func requestCancellation(ctx context.Context, peer *gateway.Session, runID strin return out } -func send(ctx context.Context, peer *gateway.Session, kind, runID string, payload any) error { +func send(ctx context.Context, peer *runtimegateway.Session, kind, runID string, payload any) error { env, err := proto.NewEnvelope(kind, runID, payload) if err != nil { return err @@ -46,11 +46,11 @@ func send(ctx context.Context, peer *gateway.Session, kind, runID string, payloa return peer.Send(ctx, env) } -func abort(peer *gateway.Session, runID string) { +func abort(peer *runtimegateway.Session, runID string) { _ = send(context.Background(), peer, proto.TypePromptCancel, runID, proto.PromptCancelPayload{}) } -func (d *Dispatcher) deliver(ctx context.Context, tenantID, sessionID string, peer *gateway.Session, request proto.PromptRequestPayload, first int64, prepared *preparedStart) (result Result, status string) { +func (d *Dispatcher) deliver(ctx context.Context, tenantID, sessionID string, peer *runtimegateway.Session, request proto.PromptRequestPayload, first int64, prepared *preparedStart) (result Result, status string) { changed, unsubscribeChanges := d.notifications.subscribe(tenantID, sessionID) defer unsubscribeChanges() status = store.TurnFailed diff --git a/services/core/internal/execution/device_authority.go b/services/core/internal/execution/device_authority.go index 3ce3df4a9..9f923feb2 100644 --- a/services/core/internal/execution/device_authority.go +++ b/services/core/internal/execution/device_authority.go @@ -3,13 +3,13 @@ package execution import ( "context" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) // authorizedRuntimePeer fences a connected socket against current credential // authority. A stable device ID does not keep an old credential alive on rotation. -func authorizedRuntimePeer(ctx context.Context, s *store.Store, registry *gateway.Registry, id string) (*gateway.Session, error) { +func authorizedRuntimePeer(ctx context.Context, s *store.Store, registry *runtimegateway.Registry, id string) (*runtimegateway.Session, error) { peer, err := registry.LookupDevice(id) if err != nil { return nil, err @@ -27,11 +27,11 @@ func authorizedRuntimePeer(ctx context.Context, s *store.Store, registry *gatewa return nil, store.ErrNotFound } if peer.IsClosed() { - return nil, gateway.ErrSessionClosed + return nil, runtimegateway.ErrSessionClosed } return peer, nil } -func (d *Dispatcher) authorizedPeer(ctx context.Context, id string) (*gateway.Session, error) { +func (d *Dispatcher) authorizedPeer(ctx context.Context, id string) (*runtimegateway.Session, error) { return authorizedRuntimePeer(ctx, d.Store, d.Registry, id) } diff --git a/services/core/internal/execution/directory_preparation.go b/services/core/internal/execution/directory_preparation.go index 2c5820dbd..55c90d76e 100644 --- a/services/core/internal/execution/directory_preparation.go +++ b/services/core/internal/execution/directory_preparation.go @@ -4,12 +4,12 @@ import ( "context" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) -func (d *Dispatcher) readPreparedDirectory(ctx context.Context, peer *gateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, read proto.WorkspaceReadPayload) directoryReadResult { +func (d *Dispatcher) readPreparedDirectory(ctx context.Context, peer *runtimegateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, read proto.WorkspaceReadPayload) directoryReadResult { owner, cancel := context.WithTimeout(ctx, 45*time.Second) defer cancel() var result directoryReadResult @@ -24,7 +24,7 @@ func (d *Dispatcher) readPreparedDirectory(ctx context.Context, peer *gateway.Se return result } -func (d *Dispatcher) withPreparedWorkspace(owner context.Context, peer *gateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, consume func(context.Context, string) error) error { +func (d *Dispatcher) withPreparedWorkspace(owner context.Context, peer *runtimegateway.Session, session store.Session, environment store.Environment, bound store.ExecutionDevice, consume func(context.Context, string) error) error { req := proto.PromptRequestPayload{AgentKind: session.Engine, AgentStateKey: "agents-api-" + session.ID, StrictResume: true, ReleaseOnCompletion: true, WorkspaceReadOnly: true} if err := d.configurePreparedEnvironment(session, environment, bound, &req); err != nil { return ErrExecutionUnavailable diff --git a/services/core/internal/execution/disabled_tools_test.go b/services/core/internal/execution/disabled_tools_test.go index 7bf0f0b06..747499919 100644 --- a/services/core/internal/execution/disabled_tools_test.go +++ b/services/core/internal/execution/disabled_tools_test.go @@ -5,10 +5,10 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine/enginetest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -38,7 +38,7 @@ func TestDisabledToolRequestPreservesIntentOnResume(t *testing.T) { } before, _ := json.Marshal(snapshot) for _, nativeID := range []string{"", "native-session"} { - request, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session"}, snapshot, device.KindCapabilities{}, store.SessionExecutionBinding{NativeSessionID: nativeID}) + request, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session"}, snapshot, runtimedevice.KindCapabilities{}, store.SessionExecutionBinding{NativeSessionID: nativeID}) if err != nil || request.ExecutionControls.DisableProgrammaticToolCalling != disabled || request.ExecutionControls.WebSearch != "disabled" || request.AgentSessionID != nativeID { t.Fatal(request, err) } @@ -68,7 +68,7 @@ func TestEnabledWebSearchNeverReachesDispatch(t *testing.T) { t.Fatal(tool, err) } snapshot := Snapshot{Agent: v1.Agent{Model: "model", Tools: tools}} - if _, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session"}, snapshot, device.KindCapabilities{}, store.SessionExecutionBinding{}); err == nil { + if _, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session"}, snapshot, runtimedevice.KindCapabilities{}, store.SessionExecutionBinding{}); err == nil { t.Fatal("dispatch request built for", tool) } raw := json.RawMessage(`{"agent":{"model":"model","tools":[` + tool + `]},"environment":{"type":"none"}}`) diff --git a/services/core/internal/execution/dispatcher.go b/services/core/internal/execution/dispatcher.go index 667105dea..392765925 100644 --- a/services/core/internal/execution/dispatcher.go +++ b/services/core/internal/execution/dispatcher.go @@ -9,8 +9,8 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -32,7 +32,7 @@ type Dispatcher struct { notifications *executionNotifications Policy Store *store.Store - Registry *gateway.Registry + Registry *runtimegateway.Registry // Options optionally supplies native adapter options for Sessions that need // no frozen model provider (environment none and legacy daemon Sessions). // The server command leaves it nil since the operator options file was diff --git a/services/core/internal/execution/environment_directory.go b/services/core/internal/execution/environment_directory.go index cbfb46264..8cbab2fa7 100644 --- a/services/core/internal/execution/environment_directory.go +++ b/services/core/internal/execution/environment_directory.go @@ -4,8 +4,8 @@ import ( "context" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -136,7 +136,7 @@ func (w *Worker) directoryDeviceReady(ctx context.Context, id, engine string, pl return known && found && info.Available && placementReady && (!prepare || (info.Capabilities.Preparation && info.Capabilities.WorkspaceReadPreparation)) } -func readEnvironmentDirectory(ctx context.Context, peer *gateway.Session, request proto.WorkspaceReadPayload) directoryReadResult { +func readEnvironmentDirectory(ctx context.Context, peer *runtimegateway.Session, request proto.WorkspaceReadPayload) directoryReadResult { result, err := peer.ListWorkspaceDirectory(ctx, request) if err == nil && result.Outcome == "completed" && result.Directory != nil && !result.Directory.Truncated && proto.ValidWorkspaceDirectory(result.Directory, request.MaxEntries) { return directoryReadResult{directory: *result.Directory} diff --git a/services/core/internal/execution/executor_preparation.go b/services/core/internal/execution/executor_preparation.go index 050e44526..7b7ccfed8 100644 --- a/services/core/internal/execution/executor_preparation.go +++ b/services/core/internal/execution/executor_preparation.go @@ -5,15 +5,15 @@ import ( "errors" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) // prepareTurnExecutor reserves one admission on the Runtime-owned Executor. // Core does not cache native ownership. A replacement requires the Runtime to // confirm cleanup and recover the exact Session history before returning ready. -func (d *Dispatcher) prepareTurnExecutor(ctx context.Context, peer *gateway.Session, tenant, session, turn string, request proto.PromptRequestPayload, expectedStatus string) (*preparedStart, error) { +func (d *Dispatcher) prepareTurnExecutor(ctx context.Context, peer *runtimegateway.Session, tenant, session, turn string, request proto.PromptRequestPayload, expectedStatus string) (*preparedStart, error) { prepared, err := newPreparedStart(peer) if err != nil { return nil, err diff --git a/services/core/internal/execution/function_images_test.go b/services/core/internal/execution/function_images_test.go index 3a055f3bb..eb6e596d4 100644 --- a/services/core/internal/execution/function_images_test.go +++ b/services/core/internal/execution/function_images_test.go @@ -5,9 +5,9 @@ import ( "errors" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -46,7 +46,7 @@ func TestFunctionImageAdmission(t *testing.T) { if err := requireFunctionResultImages(nil, "unknown", proto.FunctionResultPayload{Content: proto.TextInput("text")[0].Content}); err != nil { t.Fatal(err) } - if err := requireFunctionResultImages(&gateway.Session{}, "unknown", proto.FunctionResultPayload{Content: []proto.InputContent{{Type: "input_image", ImageURL: &image}}}); err == nil { + if err := requireFunctionResultImages(&runtimegateway.Session{}, "unknown", proto.FunctionResultPayload{Content: []proto.InputContent{{Type: "input_image", ImageURL: &image}}}); err == nil { t.Fatal("image delivery accepted without Runtime support") } } diff --git a/services/core/internal/execution/functions.go b/services/core/internal/execution/functions.go index 6118cf278..c925f10cc 100644 --- a/services/core/internal/execution/functions.go +++ b/services/core/internal/execution/functions.go @@ -8,9 +8,9 @@ import ( "fmt" "strings" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/items" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -75,7 +75,7 @@ func (f *functionExchange) record(ctx context.Context, env proto.Envelope) error return f.unlessCancelling(ctx, err) } -func (f *functionExchange) start(ctx context.Context, peer *gateway.Session) error { +func (f *functionExchange) start(ctx context.Context, peer *runtimegateway.Session) error { if f.reply != nil || len(f.tools) == 0 { return nil } @@ -184,7 +184,7 @@ func functionResult(call store.FunctionCall) (proto.FunctionResultPayload, error } // Check only this result, not ordinary function declarations or text delivery. -func requireFunctionResultImages(peer *gateway.Session, kind string, result proto.FunctionResultPayload) error { +func requireFunctionResultImages(peer *runtimegateway.Session, kind string, result proto.FunctionResultPayload) error { if !(proto.MessageInput{{Content: result.Content}}).HasImages() { return nil } diff --git a/services/core/internal/execution/mcp_support.go b/services/core/internal/execution/mcp_support.go index 1b0791c49..66a880f52 100644 --- a/services/core/internal/execution/mcp_support.go +++ b/services/core/internal/execution/mcp_support.go @@ -3,8 +3,8 @@ package execution import ( "errors" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -22,7 +22,7 @@ func (p Policy) mcpCredentialBindings(engine string, snapshot Snapshot) (map[str // Selection, final preclaim and request construction use the same combination // checks. This function never reads plaintext credentials or native configuration. -func (p Policy) mcpExecutionCredentials(engine string, snapshot Snapshot, servers []proto.MCPHTTPServer, caps device.KindCapabilities) (map[string]store.MCPCredentialBinding, error) { +func (p Policy) mcpExecutionCredentials(engine string, snapshot Snapshot, servers []proto.MCPHTTPServer, caps runtimedevice.KindCapabilities) (map[string]store.MCPCredentialBinding, error) { fail := func(message string) (map[string]store.MCPCredentialBinding, error) { return nil, errors.New(message) } diff --git a/services/core/internal/execution/mcp_support_test.go b/services/core/internal/execution/mcp_support_test.go index 3c84609cc..fffeef1f4 100644 --- a/services/core/internal/execution/mcp_support_test.go +++ b/services/core/internal/execution/mcp_support_test.go @@ -5,13 +5,13 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) -func mcpSupportFixture(t *testing.T) (Snapshot, []proto.MCPHTTPServer, device.KindCapabilities) { +func mcpSupportFixture(t *testing.T) (Snapshot, []proto.MCPHTTPServer, runtimedevice.KindCapabilities) { t.Helper() vault, credential := uuid.NewString(), uuid.NewString() tool := json.RawMessage(`{"type":"mcp","server_label":"tickets","connection_origin":"service","transport":{"type":"http","server_url":"https://mcp.example/tools"}}`) @@ -21,7 +21,7 @@ func mcpSupportFixture(t *testing.T) (Snapshot, []proto.MCPHTTPServer, device.Ki if err != nil { t.Fatal(err) } - caps := device.KindCapabilities{EnvironmentNone: true, MCPHTTPTools: true, MCPHTTPBearerAuth: true, MCPHTTPRequired: true, + caps := runtimedevice.KindCapabilities{EnvironmentNone: true, MCPHTTPTools: true, MCPHTTPBearerAuth: true, MCPHTTPRequired: true, Preparation: true} return snapshot, tools.MCP, caps } diff --git a/services/core/internal/execution/message_support.go b/services/core/internal/execution/message_support.go index c05dcfde3..f32a2ab11 100644 --- a/services/core/internal/execution/message_support.go +++ b/services/core/internal/execution/message_support.go @@ -4,9 +4,9 @@ import ( "errors" "strings" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -57,7 +57,7 @@ func validateMessageImageProfile(profile engine.Profile, _ string, input proto.M } // Image support is checked only for the operation that actually carries images. -func (p Policy) messageInputSupport(peer *gateway.Session, kind string, snapshot Snapshot, input proto.MessageInput) error { +func (p Policy) messageInputSupport(peer *runtimegateway.Session, kind string, snapshot Snapshot, input proto.MessageInput) error { if !input.HasImages() { return nil } @@ -75,7 +75,7 @@ func (p Policy) messageInputSupport(peer *gateway.Session, kind string, snapshot return requireMessageImages(peer, kind, input) } -func requireMessageImages(peer *gateway.Session, kind string, input proto.MessageInput) error { +func requireMessageImages(peer *runtimegateway.Session, kind string, input proto.MessageInput) error { if !input.HasImages() { return nil } diff --git a/services/core/internal/execution/model_execution_test.go b/services/core/internal/execution/model_execution_test.go index c593f417c..3c17e5bd9 100644 --- a/services/core/internal/execution/model_execution_test.go +++ b/services/core/internal/execution/model_execution_test.go @@ -8,7 +8,7 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -18,18 +18,18 @@ func TestSessionModelExecutionNeverFallsBack(t *testing.T) { called = true return map[string]any{"model_provider": map[string]any{"base_url": "http://127.0.0.1:1/v1"}}, nil }} - if _, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, Snapshot{ModelProviderConfigured: true}, device.KindCapabilities{}, store.SessionExecutionBinding{}); err == nil || called { + if _, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, Snapshot{ModelProviderConfigured: true}, runtimedevice.KindCapabilities{}, store.SessionExecutionBinding{}); err == nil || called { t.Fatal("missing Session credentials fell back") } // Hosted and self-hosted Runtimes have no model configuration of their own. for _, environment := range []string{"openai_hosted", "self_hosted"} { snapshot := Snapshot{Environment: &v1.Environment{Type: environment}} - if _, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, snapshot, device.KindCapabilities{}, store.SessionExecutionBinding{}); !errors.Is(err, store.ErrModelProviderRequired) || called { + if _, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, snapshot, runtimedevice.KindCapabilities{}, store.SessionExecutionBinding{}); !errors.Is(err, store.ErrModelProviderRequired) || called { t.Fatal("provider-free Session dispatched", environment, err) } } // A none device may supply its own provider environment. - request, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, Snapshot{Environment: &v1.Environment{Type: "none"}}, device.KindCapabilities{}, store.SessionExecutionBinding{}) + request, err := d.executionRequest(t.Context(), store.Session{Engine: "codex"}, Snapshot{Environment: &v1.Environment{Type: "none"}}, runtimedevice.KindCapabilities{}, store.SessionExecutionBinding{}) if err != nil || !called || request.AgentOptions["model_provider"] == nil { t.Fatal("none Session lost its adapter options", err) } diff --git a/services/core/internal/execution/preparation.go b/services/core/internal/execution/preparation.go index 0e0d2547d..ee5cccca9 100644 --- a/services/core/internal/execution/preparation.go +++ b/services/core/internal/execution/preparation.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -25,14 +25,14 @@ type preparedStart struct { startSentAt time.Time startObserved bool readyObserved bool - peer *gateway.Session + peer *runtimegateway.Session requestID string handle string executorID string - sub *gateway.Subscription + sub *runtimegateway.Subscription } -func newPreparedStart(peer *gateway.Session) (*preparedStart, error) { +func newPreparedStart(peer *runtimegateway.Session) (*preparedStart, error) { id := uuid.NewString() sub, err := peer.SubscribePreparation(id) if err != nil { diff --git a/services/core/internal/execution/recovery_test.go b/services/core/internal/execution/recovery_test.go index 7b9b500e0..3ed193273 100644 --- a/services/core/internal/execution/recovery_test.go +++ b/services/core/internal/execution/recovery_test.go @@ -3,7 +3,7 @@ package execution import ( "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -13,7 +13,7 @@ func TestExistingSessionRecoveryRequiresVerifiedCapability(t *testing.T) { for _, nativeID := range []string{"", "native"} { for _, capable := range []bool{false, true} { wantRecovery := started && nativeID == "" - req, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session", Engine: engine}, Snapshot{}, device.KindCapabilities{NativeSessionRecovery: capable}, store.SessionExecutionBinding{HasStartedTurn: started, NativeSessionID: nativeID}) + req, err := (&Dispatcher{}).executionRequest(t.Context(), store.Session{ID: "session", Engine: engine}, Snapshot{}, runtimedevice.KindCapabilities{NativeSessionRecovery: capable}, store.SessionExecutionBinding{HasStartedTurn: started, NativeSessionID: nativeID}) if wantRecovery && !capable { if err == nil { t.Fatal("unverified recovery admitted", engine) diff --git a/services/core/internal/execution/request.go b/services/core/internal/execution/request.go index 0ce8b2bb8..f784783ca 100644 --- a/services/core/internal/execution/request.go +++ b/services/core/internal/execution/request.go @@ -7,12 +7,12 @@ import ( "maps" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) -func (d *Dispatcher) executionRequest(ctx context.Context, session store.Session, snapshot Snapshot, caps device.KindCapabilities, bound store.SessionExecutionBinding) (proto.PromptRequestPayload, error) { +func (d *Dispatcher) executionRequest(ctx context.Context, session store.Session, snapshot Snapshot, caps runtimedevice.KindCapabilities, bound store.SessionExecutionBinding) (proto.PromptRequestPayload, error) { recoverNativeSession := bound.HasStartedTurn && bound.NativeSessionID == "" if recoverNativeSession && !caps.NativeSessionRecovery { return proto.PromptRequestPayload{}, errors.New("native session recovery is unavailable") diff --git a/services/core/internal/execution/runtime_compute_wake.go b/services/core/internal/execution/runtime_compute_wake.go index 7b01fefd8..9eae10eb9 100644 --- a/services/core/internal/execution/runtime_compute_wake.go +++ b/services/core/internal/execution/runtime_compute_wake.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -19,7 +19,7 @@ func (r *runtimeLifecycle) wakeCompute(ctx context.Context, p sandbox.Checkpoint } peer, err := authorizedRuntimePeer(ctx, r.store, r.registry, owner.DeviceID) if err != nil { - if !errors.Is(err, store.ErrNotFound) && !errors.Is(err, gateway.ErrDeviceNotRegistered) && !errors.Is(err, gateway.ErrSessionClosed) { + if !errors.Is(err, store.ErrNotFound) && !errors.Is(err, runtimegateway.ErrDeviceNotRegistered) && !errors.Is(err, runtimegateway.ErrSessionClosed) { return err } // This idempotent control signal is fenced by guest PID/start time and the diff --git a/services/core/internal/execution/runtime_connections.go b/services/core/internal/execution/runtime_connections.go index 501b901c9..a074dff05 100644 --- a/services/core/internal/execution/runtime_connections.go +++ b/services/core/internal/execution/runtime_connections.go @@ -6,14 +6,14 @@ import ( "github.com/google/uuid" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) // Access is serialized by the existing lifecycle gate. Durable generations fence // old observations; this map only remembers the currently observed socket. type runtimeConnection struct { - peer *gateway.Session + peer *runtimegateway.Session generation string revision int64 connected bool @@ -35,7 +35,7 @@ func (r *runtimeLifecycle) observeConnection(ctx context.Context, owner store.Ru } peer, err := authorizedRuntimePeer(ctx, r.store, r.registry, owner.DeviceID) connected := err == nil - if err != nil && !errors.Is(err, store.ErrNotFound) && !errors.Is(err, gateway.ErrSessionClosed) && !errors.Is(err, gateway.ErrDeviceNotRegistered) { + if err != nil && !errors.Is(err, store.ErrNotFound) && !errors.Is(err, runtimegateway.ErrSessionClosed) && !errors.Is(err, runtimegateway.ErrDeviceNotRegistered) { return err } return observeRuntimeConnection(ctx, r.store, r.connections, owner.TenantID, owner.EnvironmentID, peer, connected) @@ -43,7 +43,7 @@ func (r *runtimeLifecycle) observeConnection(ctx context.Context, owner store.Ru // Each Environment has one observer: the hosted lifecycle or the Worker loop for // enrolled user compute. Both publish the same durable generation/revision rules. -func observeRuntimeConnection(ctx context.Context, s *store.Store, connections map[string]*runtimeConnection, tenant, environment string, peer *gateway.Session, connected bool) error { +func observeRuntimeConnection(ctx context.Context, s *store.Store, connections map[string]*runtimeConnection, tenant, environment string, peer *runtimegateway.Session, connected bool) error { current := connections[environment] if connected && (current == nil || current.peer != peer) { generation := uuid.NewString() @@ -74,7 +74,7 @@ func (w *Worker) observeEnrolledRuntimes(ctx context.Context) error { live[bound.EnvironmentID] = true peer, err := w.dispatcher.authorizedPeer(ctx, bound.DeviceID) connected := err == nil - if err != nil && !errors.Is(err, store.ErrNotFound) && !errors.Is(err, gateway.ErrSessionClosed) && !errors.Is(err, gateway.ErrDeviceNotRegistered) { + if err != nil && !errors.Is(err, store.ErrNotFound) && !errors.Is(err, runtimegateway.ErrSessionClosed) && !errors.Is(err, runtimegateway.ErrDeviceNotRegistered) { return err } if err := observeRuntimeConnection(ctx, w.dispatcher.Store, w.enrolledConnections, bound.TenantID, bound.EnvironmentID, peer, connected); err != nil { diff --git a/services/core/internal/execution/runtime_initialization.go b/services/core/internal/execution/runtime_initialization.go index 8ec8597db..7bc7bf7c5 100644 --- a/services/core/internal/execution/runtime_initialization.go +++ b/services/core/internal/execution/runtime_initialization.go @@ -8,8 +8,8 @@ import ( "time" "github.com/MiniMax-AI/OpenAgentCore/internal/agentcapabilities" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -57,7 +57,7 @@ func (w *Worker) runEnvironmentInitializations(ctx context.Context) error { } peer, err := w.dispatcher.authorizedPeer(ctx, owner.DeviceID) if err != nil { - if errors.Is(err, store.ErrNotFound) || errors.Is(err, gateway.ErrSessionClosed) || errors.Is(err, gateway.ErrDeviceNotRegistered) { + if errors.Is(err, store.ErrNotFound) || errors.Is(err, runtimegateway.ErrSessionClosed) || errors.Is(err, runtimegateway.ErrDeviceNotRegistered) { continue } return err diff --git a/services/core/internal/execution/runtime_lifecycle.go b/services/core/internal/execution/runtime_lifecycle.go index 0f0aefabf..b09dda19f 100644 --- a/services/core/internal/execution/runtime_lifecycle.go +++ b/services/core/internal/execution/runtime_lifecycle.go @@ -11,9 +11,9 @@ import ( "github.com/google/uuid" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -41,7 +41,7 @@ type RuntimeProvider struct { type runtimeLifecycle struct { store *store.Store - registry *gateway.Registry + registry *runtimegateway.Registry config RuntimeProvider nodeID string gate chan struct{} @@ -55,7 +55,7 @@ type runtimeLifecycle struct { wakeHints chan struct{} } -func newRuntimeManager(s *store.Store, registry *gateway.Registry, config *RuntimeProvider) (*runtimeManager, error) { +func newRuntimeManager(s *store.Store, registry *runtimegateway.Registry, config *RuntimeProvider) (*runtimeManager, error) { if config == nil { return nil, nil } @@ -76,7 +76,7 @@ func newRuntimeManager(s *store.Store, registry *gateway.Registry, config *Runti return &runtimeManager{store: s, registry: registry, config: copied, setupInstallationID: config.InstallationID, loadDeployment: config.loadDeployment, prepareDeployment: config.prepareDeployment, publishUnconfigured: config.PublishUnconfigured, setupGate: make(chan struct{}, 1), mutationGate: make(chan struct{}, 1), ctx: ctx, cancel: stop, nodes: make(map[string]*runtimeNode), failed: make(chan error, 1), inventory: make(chan struct{}, 1)}, nil } -func validatedRuntimeProvider(config *RuntimeProvider, registry *gateway.Registry) (RuntimeProvider, error) { +func validatedRuntimeProvider(config *RuntimeProvider, registry *runtimegateway.Registry) (RuntimeProvider, error) { u, err := url.Parse(config.CoreURL) if err != nil || u.Host == "" || (u.Scheme != "http" && u.Scheme != "https") || u.User != nil || u.RawQuery != "" || u.Fragment != "" || config.Provider == nil || registry == nil { return RuntimeProvider{}, sandbox.ErrInvalid @@ -202,7 +202,7 @@ func (r *runtimeLifecycle) provision(ctx context.Context, tenant, environment, p return store.RuntimeAllocation{}, err } token := hex.EncodeToString(secret) - owner, err := r.store.ReserveRuntimeAllocation(ctx, tenant, environment, providerKey, device.HashCredential(token)) + owner, err := r.store.ReserveRuntimeAllocation(ctx, tenant, environment, providerKey, runtimedevice.HashCredential(token)) if err != nil { return owner, err } diff --git a/services/core/internal/execution/runtime_manager.go b/services/core/internal/execution/runtime_manager.go index 68fb2f4b3..4851bbc91 100644 --- a/services/core/internal/execution/runtime_manager.go +++ b/services/core/internal/execution/runtime_manager.go @@ -7,7 +7,7 @@ import ( "sync" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -17,7 +17,7 @@ var errRuntimeTransition = fmt.Errorf("%w: sandbox configuration is changing", E type runtimeManager struct { store *store.Store - registry *gateway.Registry + registry *runtimegateway.Registry config RuntimeProvider setupInstallationID string loadDeployment func(context.Context) (*RuntimeProvider, error) diff --git a/services/core/internal/execution/sandbox_deployment_drain_test.go b/services/core/internal/execution/sandbox_deployment_drain_test.go index 93f01d3dd..e6492062b 100644 --- a/services/core/internal/execution/sandbox_deployment_drain_test.go +++ b/services/core/internal/execution/sandbox_deployment_drain_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -107,7 +107,7 @@ func testLifecycleCancellationPreservesLease(t *testing.T, mode string) { defer hub.Close() id := uuid.NewString() configuration := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", Mode: "nodes", Generation: 1, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(lease.Store(), gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return configuration, nil })) + m, err := newRuntimeManager(lease.Store(), runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return configuration, nil })) if err != nil { t.Fatal(err) } @@ -245,7 +245,7 @@ func TestSandboxDeploymentDrainFailureCannotReactivate(t *testing.T) { defer hub.Close() id := uuid.NewString() configuration := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", Mode: "nodes", Generation: 1, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(lease.Store(), gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return configuration, nil })) + m, err := newRuntimeManager(lease.Store(), runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return configuration, nil })) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/sandbox_deployment_setup_test.go b/services/core/internal/execution/sandbox_deployment_setup_test.go index e7e9b9098..084087c8e 100644 --- a/services/core/internal/execution/sandbox_deployment_setup_test.go +++ b/services/core/internal/execution/sandbox_deployment_setup_test.go @@ -11,7 +11,7 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" @@ -25,7 +25,7 @@ func TestDeferredSandboxDeploymentLoadsOnceBeforeNodeCreation(t *testing.T) { var selected atomic.Bool var loads atomic.Int32 configuration := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { loads.Add(1) if !selected.Load() { return nil, nil @@ -70,7 +70,7 @@ func TestDeferredSandboxDeploymentLoadsOnceBeforeNodeCreation(t *testing.T) { func TestDeferredSandboxDeploymentShutdownCancelsLoad(t *testing.T) { entered := make(chan struct{}) - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(uuid.NewString(), func(ctx context.Context) (*RuntimeProvider, error) { + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(uuid.NewString(), func(ctx context.Context) (*RuntimeProvider, error) { close(entered) <-ctx.Done() return nil, ctx.Err() @@ -95,7 +95,7 @@ func TestDeferredSandboxProviderFailureKeepsRecoveryAvailable(t *testing.T) { available := false loadErr := ErrExecutionUnavailable configuration := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { if !available { return nil, loadErr } @@ -127,7 +127,7 @@ func TestRejectedSandboxCandidatePreservesActiveGeneration(t *testing.T) { id := uuid.NewString() config := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", Mode: "nodes", Generation: 1, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} rejected := errors.New("candidate provider unavailable") - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil }, + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil }, func(context.Context, store.SandboxSetup) (PreparedRuntimeDeployment, error) { return PreparedRuntimeDeployment{}, rejected })) @@ -159,7 +159,7 @@ func TestRejectedSandboxCandidatePreservesActiveGeneration(t *testing.T) { func TestSandboxCandidateValidationDoesNotHoldManagerLock(t *testing.T) { id := uuid.NewString() entered, release := make(chan struct{}), make(chan struct{}) - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, nil }, + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, nil }, func(context.Context, store.SandboxSetup) (PreparedRuntimeDeployment, error) { close(entered) <-release @@ -192,7 +192,7 @@ func TestCommittedSandboxCandidatePublishesAfterShutdown(t *testing.T) { hub := node.NewHub(node.HubOptions{}) defer hub.Close() id := uuid.NewString() - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, nil })) + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, nil })) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/sandbox_deployment_switch_test.go b/services/core/internal/execution/sandbox_deployment_switch_test.go index dcacef4de..ae14dac09 100644 --- a/services/core/internal/execution/sandbox_deployment_switch_test.go +++ b/services/core/internal/execution/sandbox_deployment_switch_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -18,7 +18,7 @@ func TestSandboxManagerSwitchDrainsBeforeDirectActivation(t *testing.T) { defer hub.Close() id := uuid.NewString() config := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", Mode: "nodes", Generation: 1, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) if err != nil { t.Fatal(err) } @@ -79,7 +79,7 @@ func TestSandboxManagerSwitchDrainsBeforeDirectActivation(t *testing.T) { func TestSandboxManagerFailedActivationStaysPaused(t *testing.T) { id := uuid.NewString() - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, errors.New("provider unavailable") })) + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, errors.New("provider unavailable") })) if err != nil { t.Fatal(err) } @@ -100,7 +100,7 @@ func TestSandboxManagerCancelledSwitchCannotResumeBeforeDrain(t *testing.T) { defer hub.Close() id := uuid.NewString() config := &RuntimeProvider{InstallationID: id, ProviderKind: "docker", Mode: "nodes", Generation: 1, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: hub.Proxy(uuid.NewString(), "docker", 1)} - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) if err != nil { t.Fatal(err) } @@ -154,7 +154,7 @@ func TestSandboxActivationCannotBypassOutstandingDrain(t *testing.T) { hub := node.NewHub(node.HubOptions{}) defer hub.Close() id := uuid.NewString() - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return nil, nil }, func(_ context.Context, setup store.SandboxSetup) (PreparedRuntimeDeployment, error) { return PreparedRuntimeDeployment{Config: &RuntimeProvider{InstallationID: setup.InstallationID, ProviderKind: setup.Provider, Mode: setup.Mode, CoreURL: "https://core.example/api/v1", BackendFingerprint: setup.BackendFingerprint, Provider: hub.Proxy(uuid.NewString(), "docker", 1)}}, nil diff --git a/services/core/internal/execution/sandbox_generations_test.go b/services/core/internal/execution/sandbox_generations_test.go index 48b39aa87..88f1ad9d8 100644 --- a/services/core/internal/execution/sandbox_generations_test.go +++ b/services/core/internal/execution/sandbox_generations_test.go @@ -5,8 +5,8 @@ import ( "errors" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" @@ -50,7 +50,7 @@ func TestE2BReplacementVerifiesTwiceAndNeverPublishesFailedCommit(t *testing.T) }, FenceCredential: func(context.Context) (func(), error) { fenced++; return func() { released++ }, nil }, Publish: func(*RuntimeProvider) { published++ }}, nil }) - m, err := newRuntimeManager(writer, gateway.NewRegistry(), config) + m, err := newRuntimeManager(writer, runtimegateway.NewRegistry(), config) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/sandbox_provider_contract_test.go b/services/core/internal/execution/sandbox_provider_contract_test.go index 34286419f..a73cd482f 100644 --- a/services/core/internal/execution/sandbox_provider_contract_test.go +++ b/services/core/internal/execution/sandbox_provider_contract_test.go @@ -5,7 +5,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/google/uuid" ) @@ -18,7 +18,7 @@ func TestSandboxProviderRegistrationDoesNotRequireAnExecutionVendorBranch(t *tes id := uuid.NewString() config := &RuntimeProvider{InstallationID: id, ProviderKind: "contract-fixture", Mode: mode, CoreURL: "https://core.example/api/v1", BackendFingerprint: strings.Repeat("a", 64), Provider: &lifecycleOnlySandbox{}} - m, err := newRuntimeManager(nil, gateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) + m, err := newRuntimeManager(nil, runtimegateway.NewRegistry(), NewDeferredRuntimeProvider(id, func(context.Context) (*RuntimeProvider, error) { return config, nil })) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/sandbox_reset_test.go b/services/core/internal/execution/sandbox_reset_test.go index e6dd6dbd9..b23e8920f 100644 --- a/services/core/internal/execution/sandbox_reset_test.go +++ b/services/core/internal/execution/sandbox_reset_test.go @@ -10,9 +10,9 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -111,7 +111,7 @@ func TestSandboxResetPageTimeoutRecoversCommittedOwner(t *testing.T) { } return &RuntimeProvider{InstallationID: id, ProviderKind: setup.Provider, Mode: setup.Mode, Generation: setup.Generation, CoreURL: "https://core.example/api/v1", BackendFingerprint: setup.BackendFingerprint, Provider: hub.Proxy(uuid.NewString(), "docker", 1)}, nil }) - m, err := newRuntimeManager(w, gateway.NewRegistry(), config) + m, err := newRuntimeManager(w, runtimegateway.NewRegistry(), config) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/sandbox_snapshot_budget_test.go b/services/core/internal/execution/sandbox_snapshot_budget_test.go index c81f8bdf5..4e52b91c3 100644 --- a/services/core/internal/execution/sandbox_snapshot_budget_test.go +++ b/services/core/internal/execution/sandbox_snapshot_budget_test.go @@ -10,8 +10,8 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/node" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -84,7 +84,7 @@ func TestSandboxResetSnapshotFitsPageBudget(t *testing.T) { } return &RuntimeProvider{InstallationID: id, ProviderKind: setup.Provider, Generation: setup.Generation, Mode: setup.Mode, CoreURL: "https://core.example/api/v1", BackendFingerprint: setup.BackendFingerprint, Provider: hub.Proxy(uuid.NewString(), "docker", 1)}, nil }) - m, err := newRuntimeManager(w, gateway.NewRegistry(), configuration) + m, err := newRuntimeManager(w, runtimegateway.NewRegistry(), configuration) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/execution/structured_output_test.go b/services/core/internal/execution/structured_output_test.go index 916c8b64a..7d3ecd9a3 100644 --- a/services/core/internal/execution/structured_output_test.go +++ b/services/core/internal/execution/structured_output_test.go @@ -6,10 +6,10 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine/enginetest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -32,7 +32,7 @@ func TestStructuredOutputRequestKeepsFrozenSchemaAndInstructions(t *testing.T) { schema := json.RawMessage(`{"type":"object","properties":{"number":{"const":9007199254740992}}}`) instructions := "Keep these original instructions." snapshot := Snapshot{Agent: v1.Agent{Model: "model", Instructions: &instructions, Text: v1.TextConfig{Format: v1.TextFormat{Type: "json_schema", Schema: schema}}}} - request, err := (&Dispatcher{}).executionRequest(context.Background(), store.Session{}, snapshot, device.KindCapabilities{MessageItems: true}, store.SessionExecutionBinding{}) + request, err := (&Dispatcher{}).executionRequest(context.Background(), store.Session{}, snapshot, runtimedevice.KindCapabilities{MessageItems: true}, store.SessionExecutionBinding{}) if err != nil || request.ExecutionControls.OutputFormat == nil { t.Fatal(err) } diff --git a/services/core/internal/execution/support.go b/services/core/internal/execution/support.go index 139729a19..c0eab56c5 100644 --- a/services/core/internal/execution/support.go +++ b/services/core/internal/execution/support.go @@ -5,9 +5,9 @@ import ( "errors" "strings" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -78,16 +78,16 @@ func (p Policy) validateEngineInputs(engine string, configuration json.RawMessag // engineCapabilities is shared by device selection and the final preclaim check. // Capability bits describe the adapter; supported values still depend on its profile. -func (p Policy) engineCapabilities(peer *gateway.Session, engine string, snapshot Snapshot) (device.KindCapabilities, error) { - fail := func(message string) (device.KindCapabilities, error) { - return device.KindCapabilities{}, errors.New(message) +func (p Policy) engineCapabilities(peer *runtimegateway.Session, engine string, snapshot Snapshot) (runtimedevice.KindCapabilities, error) { + fail := func(message string) (runtimedevice.KindCapabilities, error) { + return runtimedevice.KindCapabilities{}, errors.New(message) } profile, ok := p.Engines.Lookup(engine) if !ok || (snapshot.Environment != nil && !profile.Accepts(snapshot.Environment.Type)) { return fail("execution engine placement is not supported") } if err := validateProfileConfiguration(profile, snapshot); err != nil { - return device.KindCapabilities{}, err + return runtimedevice.KindCapabilities{}, err } info, found, known := peer.AgentKindStatus(engine) caps := info.Capabilities @@ -132,7 +132,7 @@ func (p Policy) engineCapabilities(peer *gateway.Session, engine string, snapsho return fail("device must advertise function_tools") } if _, err := p.mcpExecutionCredentials(engine, snapshot, tools.MCP, caps); err != nil { - return device.KindCapabilities{}, err + return runtimedevice.KindCapabilities{}, err } if snapshot.Environment != nil && (snapshot.Environment.Type == "openai_hosted" || snapshot.Environment.Type == "self_hosted") { if !caps.Preparation || !caps.LocalEnvironment || !caps.WorkspaceReadPreparation || !caps.WorkspaceOutputExport { diff --git a/services/core/internal/runtime/gateway.go b/services/core/internal/runtime/gateway.go index 13201fa38..84d131ae8 100644 --- a/services/core/internal/runtime/gateway.go +++ b/services/core/internal/runtime/gateway.go @@ -8,34 +8,34 @@ import ( "github.com/go-chi/chi/v5" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" ) type DeviceStore interface { - gateway.RuntimeStore - gateway.HeartbeatTouch + runtimegateway.RuntimeStore + runtimegateway.HeartbeatTouch } // NewGateway serves the V1 daemon executor transport for both managed and // user-managed Runtime. Its credentials never grant public Session API access. -func NewGateway(s DeviceStore, publicWSURL string) (http.Handler, *gateway.Registry, error) { +func NewGateway(s DeviceStore, publicWSURL string) (http.Handler, *runtimegateway.Registry, error) { u, err := url.Parse(publicWSURL) if err != nil || s == nil || (u.Scheme != "ws" && u.Scheme != "wss") || u.Hostname() == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" || u.Path != "/api/v1/agent-daemon/ws" { return nil, nil, errors.New("daemon URL must be an absolute ws(s) URL ending in /api/v1/agent-daemon/ws") } - registry := gateway.NewRegistry() - h := gateway.NewHandler(gateway.HandlerConfig{ - Authenticator: gateway.NewAuthenticator(s), Registry: registry, + registry := runtimegateway.NewRegistry() + h := runtimegateway.NewHandler(runtimegateway.HandlerConfig{ + Authenticator: runtimegateway.NewAuthenticator(s), Registry: registry, Heartbeat: s, PublicWSURL: publicWSURL, }) r := chi.NewRouter() - r.Route("/api/v1", func(r chi.Router) { gateway.RegisterRoutes(r, h) }) + r.Route("/api/v1", func(r chi.Router) { runtimegateway.RegisterRoutes(r, h) }) return r, registry, nil } // CloseConnections releases upgraded WebSockets, which http.Server.Shutdown // does not close. Call after stopping new HTTP upgrades. -func CloseConnections(registry *gateway.Registry) { +func CloseConnections(registry *runtimegateway.Registry) { for _, id := range registry.Devices() { if session, err := registry.LookupDevice(id); err == nil { session.Close("execution service shutting down") diff --git a/internal/agentdaemon/device/cancellation.go b/services/core/internal/runtimedevice/cancellation.go similarity index 95% rename from internal/agentdaemon/device/cancellation.go rename to services/core/internal/runtimedevice/cancellation.go index 791f8b3b2..b747cd462 100644 --- a/internal/agentdaemon/device/cancellation.go +++ b/services/core/internal/runtimedevice/cancellation.go @@ -1,4 +1,4 @@ -package device +package runtimedevice import "time" diff --git a/internal/agentdaemon/device/credential.go b/services/core/internal/runtimedevice/credential.go similarity index 97% rename from internal/agentdaemon/device/credential.go rename to services/core/internal/runtimedevice/credential.go index cefa69303..daede9156 100644 --- a/internal/agentdaemon/device/credential.go +++ b/services/core/internal/runtimedevice/credential.go @@ -1,4 +1,4 @@ -package device +package runtimedevice import ( "crypto/sha256" diff --git a/internal/agentdaemon/device/state.go b/services/core/internal/runtimedevice/state.go similarity index 99% rename from internal/agentdaemon/device/state.go rename to services/core/internal/runtimedevice/state.go index 02b71c726..6bb39ecfa 100644 --- a/internal/agentdaemon/device/state.go +++ b/services/core/internal/runtimedevice/state.go @@ -1,5 +1,5 @@ // Package device defines persistence data shared by daemon gateways and their stores. -package device +package runtimedevice import "time" diff --git a/services/core/internal/runtimeenrollment/connection.go b/services/core/internal/runtimeenrollment/connection.go index 4bd3f780d..ae35cdee5 100644 --- a/services/core/internal/runtimeenrollment/connection.go +++ b/services/core/internal/runtimeenrollment/connection.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -18,12 +18,12 @@ type ConnectionStore interface { AuthenticateEnvironmentExecutor(context.Context, string, string) (string, error) GetEnvironment(context.Context, string, string) (store.Environment, error) GetSessionDevice(context.Context, string, string) (store.ExecutionDevice, error) - GetDeviceCredential(context.Context, string) (device.Credential, bool, error) + GetDeviceCredential(context.Context, string) (runtimedevice.Credential, bool, error) } // ConnectionHandler observes an existing binding without enrollment or execution. // Executor authority never grants access to the public Session API. -func ConnectionHandler(s ConnectionStore, registry *gateway.Registry) http.Handler { +func ConnectionHandler(s ConnectionStore, registry *runtimegateway.Registry) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Cache-Control", "no-store") fail := func(status int) { http.Error(w, http.StatusText(status), status) } @@ -43,7 +43,7 @@ func ConnectionHandler(s ConnectionStore, registry *gateway.Registry) http.Handl return } environment := query.Get("environment_id") - digest := device.HashCredential(authorization[1]) + digest := runtimedevice.HashCredential(authorization[1]) ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second) defer cancel() connected, err := RuntimeConnected(ctx, s, registry, environment, digest) @@ -70,7 +70,7 @@ func ConnectionHandler(s ConnectionStore, registry *gateway.Registry) http.Handl // RuntimeConnected observes current executor authority and a matching open peer. // It rechecks authority after the peer; callers must not supply a stale transaction. -func RuntimeConnected(ctx context.Context, s ConnectionStore, registry *gateway.Registry, environment, digest string) (bool, error) { +func RuntimeConnected(ctx context.Context, s ConnectionStore, registry *runtimegateway.Registry, environment, digest string) (bool, error) { tenant, err := s.AuthenticateEnvironmentExecutor(ctx, environment, digest) if err != nil { return false, err @@ -106,7 +106,7 @@ func RuntimeConnected(ctx context.Context, s ConnectionStore, registry *gateway. return false, nil } peer, err := registry.LookupDevice(bound.ID) - if errors.Is(err, gateway.ErrDeviceNotRegistered) { + if errors.Is(err, runtimegateway.ErrDeviceNotRegistered) { return false, nil } if err != nil { diff --git a/services/core/internal/runtimeenrollment/connection_test.go b/services/core/internal/runtimeenrollment/connection_test.go index e1c1d5a41..a713cdb73 100644 --- a/services/core/internal/runtimeenrollment/connection_test.go +++ b/services/core/internal/runtimeenrollment/connection_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -23,7 +23,7 @@ type connectionStub struct { func (s *connectionStub) AuthenticateEnvironmentExecutor(_ context.Context, environment, digest string) (string, error) { s.calls++ - if environment != "environment" || digest != device.HashCredential("test-key") { + if environment != "environment" || digest != runtimedevice.HashCredential("test-key") { return "", store.ErrNotFound } return "tenant", s.err @@ -34,7 +34,7 @@ func (*connectionStub) GetEnvironment(context.Context, string, string) (store.En func (*connectionStub) GetSessionDevice(context.Context, string, string) (store.ExecutionDevice, error) { return store.ExecutionDevice{}, store.ErrNotFound } -func (*connectionStub) GetDeviceCredential(context.Context, string) (device.Credential, bool, error) { +func (*connectionStub) GetDeviceCredential(context.Context, string) (runtimedevice.Credential, bool, error) { panic("unbound lookup") } @@ -57,7 +57,7 @@ func TestConnectionReadContract(t *testing.T) { req := httptest.NewRequest(tc.method, "/api/v1/agent-daemon/connection?"+tc.query, nil) req.Header.Set("Authorization", tc.bearer) res := httptest.NewRecorder() - ConnectionHandler(s, gateway.NewRegistry()).ServeHTTP(res, req) + ConnectionHandler(s, runtimegateway.NewRegistry()).ServeHTTP(res, req) if res.Code != tc.code || s.calls != tc.calls || res.Header().Get("Cache-Control") != "no-store" { t.Fatalf("%s %s: %d, %d calls", tc.method, tc.query, res.Code, s.calls) } @@ -100,23 +100,23 @@ func (s *liveConnectionStore) GetEnvironment(context.Context, string, string) (s func (s *liveConnectionStore) GetSessionDevice(context.Context, string, string) (store.ExecutionDevice, error) { return store.ExecutionDevice{ID: "device", EnvironmentID: "environment"}, nil } -func (s *liveConnectionStore) GetDeviceCredential(context.Context, string) (device.Credential, bool, error) { +func (s *liveConnectionStore) GetDeviceCredential(context.Context, string) (runtimedevice.Credential, bool, error) { s.credentialCalls++ if s.authCalls >= 2 && s.credentialRecheckError != nil { - return device.Credential{}, false, s.credentialRecheckError + return runtimedevice.Credential{}, false, s.credentialRecheckError } if s.deviceRevokedAtRecheck && s.authCalls >= 2 { - return device.Credential{}, false, nil + return runtimedevice.Credential{}, false, nil } - return device.Credential{ID: "device", WorkspaceID: "tenant", Type: gateway.RuntimeTypeAgentDaemon, CredentialHash: s.digest}, true, nil + return runtimedevice.Credential{ID: "device", WorkspaceID: "tenant", Type: runtimegateway.RuntimeTypeAgentDaemon, CredentialHash: s.digest}, true, nil } func TestRuntimeConnectedCurrentAuthorityAfterPeer(t *testing.T) { for _, name := range []string{"connected", "rotated before read", "revoked after peer", "device revoked after peer", "retired after peer", "store error after peer", "device store error after peer", "closed", "no registry"} { t.Run(name, func(t *testing.T) { - digest := device.HashCredential("fixture-key") + digest := runtimedevice.HashCredential("fixture-key") s := &liveConnectionStore{digest: digest} - registry := gateway.NewRegistry() - handler := gateway.NewHandler(gateway.HandlerConfig{Registry: registry, Authenticator: gateway.NewAuthenticator(s)}) + registry := runtimegateway.NewRegistry() + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Registry: registry, Authenticator: runtimegateway.NewAuthenticator(s)}) server := httptest.NewServer(http.HandlerFunc(handler.WS)) defer server.Close() conn, _, err := websocket.DefaultDialer.Dial("ws"+strings.TrimPrefix(server.URL, "http")+"?device_id=device&version="+proto.Version, http.Header{"Authorization": {"Bearer fixture-key"}}) @@ -137,7 +137,7 @@ func TestRuntimeConnectedCurrentAuthorityAfterPeer(t *testing.T) { want := name == "connected" switch name { case "rotated before read": - s.digest = device.HashCredential("new-key") + s.digest = runtimedevice.HashCredential("new-key") digest = s.digest case "revoked after peer": s.revokeAtRecheck = true diff --git a/services/core/internal/runtimeenrollment/enrollment.go b/services/core/internal/runtimeenrollment/enrollment.go index f7b970af1..5c33f463f 100644 --- a/services/core/internal/runtimeenrollment/enrollment.go +++ b/services/core/internal/runtimeenrollment/enrollment.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -43,7 +43,7 @@ func EnrollmentHandler(s EnrollmentStore) http.Handler { } ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second) defer cancel() - binding, err := s.EnrollRuntime(ctx, input.EnvironmentID, device.HashCredential(authorization[1])) + binding, err := s.EnrollRuntime(ctx, input.EnvironmentID, runtimedevice.HashCredential(authorization[1])) switch { case errors.Is(err, store.ErrNotFound): fail(http.StatusUnauthorized) diff --git a/services/core/internal/runtimeenrollment/enrollment_test.go b/services/core/internal/runtimeenrollment/enrollment_test.go index a216c606d..eb73fc0b7 100644 --- a/services/core/internal/runtimeenrollment/enrollment_test.go +++ b/services/core/internal/runtimeenrollment/enrollment_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -18,7 +18,7 @@ type enrollmentStub struct { func (s *enrollmentStub) EnrollRuntime(_ context.Context, environment, digest string) (store.RuntimeEnrollment, error) { s.calls++ - if environment != "environment" || digest != device.HashCredential("private-test-token") { + if environment != "environment" || digest != runtimedevice.HashCredential("private-test-token") { return store.RuntimeEnrollment{}, errors.New("unexpected enrollment input") } return store.RuntimeEnrollment{DeviceID: "device", SessionID: "session", EnvironmentID: environment, WorkspaceDirectory: "/workspace"}, s.err diff --git a/internal/agentdaemon/gateway/auth.go b/services/core/internal/runtimegateway/auth.go similarity index 92% rename from internal/agentdaemon/gateway/auth.go rename to services/core/internal/runtimegateway/auth.go index b6f02291c..e20bed650 100644 --- a/internal/agentdaemon/gateway/auth.go +++ b/services/core/internal/runtimegateway/auth.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -6,7 +6,7 @@ import ( "errors" "fmt" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) // RuntimeTypeAgentDaemon is the value runtimes.type takes for rows @@ -31,7 +31,7 @@ var ErrAuthIncompatibleVersion = errors.New("agentdaemon auth: incompatible prot // RuntimeStore supplies device credentials without exposing product runtime records. type RuntimeStore interface { - GetDeviceCredential(ctx context.Context, runtimeID string) (device.Credential, bool, error) + GetDeviceCredential(ctx context.Context, runtimeID string) (runtimedevice.Credential, bool, error) } // AuthenticatedRuntime is the result of a successful credential check. @@ -81,7 +81,7 @@ func (a *Authenticator) AuthenticateBearer(ctx context.Context, deviceID, bearer // out-of-band. Fail closed. return AuthenticatedRuntime{}, ErrAuthBadCredential } - presented := device.HashCredential(bearer) + presented := runtimedevice.HashCredential(bearer) if subtle.ConstantTimeCompare([]byte(presented), []byte(storedHash)) != 1 { return AuthenticatedRuntime{}, ErrAuthBadCredential } diff --git a/internal/agentdaemon/gateway/auth_test.go b/services/core/internal/runtimegateway/auth_test.go similarity index 85% rename from internal/agentdaemon/gateway/auth_test.go rename to services/core/internal/runtimegateway/auth_test.go index 60274b87a..a480baf43 100644 --- a/internal/agentdaemon/gateway/auth_test.go +++ b/services/core/internal/runtimegateway/auth_test.go @@ -1,20 +1,20 @@ -package gateway +package runtimegateway import ( "context" "errors" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) type stubRuntimeStore struct { - row device.Credential + row runtimedevice.Credential ok bool getErr error } -func (s *stubRuntimeStore) GetDeviceCredential(_ context.Context, _ string) (device.Credential, bool, error) { +func (s *stubRuntimeStore) GetDeviceCredential(_ context.Context, _ string) (runtimedevice.Credential, bool, error) { return s.row, s.ok, s.getErr } @@ -42,10 +42,10 @@ func TestAuthenticator_RejectsWrongRuntimeType(t *testing.T) { // A legacy local runtime row trying to dial in as agent_daemon // must fail — otherwise a paired local credential could open an // agent_daemon WS and bypass the device picker. - row := device.Credential{ + row := runtimedevice.Credential{ ID: "dev-1", Type: "local", - CredentialHash: device.HashCredential("tok"), + CredentialHash: runtimedevice.HashCredential("tok"), } auth := NewAuthenticator(&stubRuntimeStore{row: row, ok: true}) _, err := auth.AuthenticateBearer(context.Background(), "dev-1", "tok") @@ -55,10 +55,10 @@ func TestAuthenticator_RejectsWrongRuntimeType(t *testing.T) { } func TestAuthenticator_RejectsBadCredential(t *testing.T) { - row := device.Credential{ + row := runtimedevice.Credential{ ID: "dev-1", Type: RuntimeTypeAgentDaemon, - CredentialHash: device.HashCredential("real-tok"), + CredentialHash: runtimedevice.HashCredential("real-tok"), } auth := NewAuthenticator(&stubRuntimeStore{row: row, ok: true}) _, err := auth.AuthenticateBearer(context.Background(), "dev-1", "wrong-tok") @@ -78,12 +78,12 @@ func TestAuthenticator_RejectsBadCredential(t *testing.T) { } func TestAuthenticator_AcceptsValidCredential(t *testing.T) { - row := device.Credential{ + row := runtimedevice.Credential{ ID: "dev-1", WorkspaceID: "wks-1", Name: "alice-mac", Type: RuntimeTypeAgentDaemon, - CredentialHash: device.HashCredential("real-tok"), + CredentialHash: runtimedevice.HashCredential("real-tok"), } auth := NewAuthenticator(&stubRuntimeStore{row: row, ok: true}) got, err := auth.AuthenticateBearer(context.Background(), "dev-1", "real-tok") diff --git a/internal/agentdaemon/gateway/bootstrap_url_test.go b/services/core/internal/runtimegateway/bootstrap_url_test.go similarity index 78% rename from internal/agentdaemon/gateway/bootstrap_url_test.go rename to services/core/internal/runtimegateway/bootstrap_url_test.go index fcbab730e..70f379122 100644 --- a/internal/agentdaemon/gateway/bootstrap_url_test.go +++ b/services/core/internal/runtimegateway/bootstrap_url_test.go @@ -1,7 +1,7 @@ -package gateway +package runtimegateway import ( - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "net/http" "net/http/httptest" "strings" @@ -13,7 +13,7 @@ func TestBootstrapPublishesURLOnlyAfterAuthentication(t *testing.T) { const publicURL = "wss://core.example/api/v1/agent-daemon/ws" for _, valid := range []bool{true, false} { h := NewHandler(HandlerConfig{Registry: NewRegistry(), PublicWSURL: publicURL, - Authenticator: NewAuthenticator(&stubRuntimeStore{ok: true, row: device.Credential{ID: "device", WorkspaceID: "tenant", Type: RuntimeTypeAgentDaemon, CredentialHash: device.HashCredential(token)}})}) + Authenticator: NewAuthenticator(&stubRuntimeStore{ok: true, row: runtimedevice.Credential{ID: "device", WorkspaceID: "tenant", Type: RuntimeTypeAgentDaemon, CredentialHash: runtimedevice.HashCredential(token)}})}) r := httptest.NewRequest(http.MethodPost, "/agent-daemon/bootstrap", strings.NewReader(`{"device_id":"device"}`)) bearer, status := "wrong", http.StatusUnauthorized if valid { diff --git a/internal/agentdaemon/gateway/cancellation.go b/services/core/internal/runtimegateway/cancellation.go similarity index 95% rename from internal/agentdaemon/gateway/cancellation.go rename to services/core/internal/runtimegateway/cancellation.go index ae62ff1f7..cf1f2f6d5 100644 --- a/internal/agentdaemon/gateway/cancellation.go +++ b/services/core/internal/runtimegateway/cancellation.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -6,14 +6,14 @@ import ( "sync" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) // ArchivedCancellationStore is deliberately separate from RuntimeStore: a // receipt opportunity cannot authenticate a new connection or authorize work. type ArchivedCancellationStore interface { - ArchivedCancellationReceipt(context.Context, string, string, []string) (device.ArchivedCancellationReceipt, error) + ArchivedCancellationReceipt(context.Context, string, string, []string) (runtimedevice.ArchivedCancellationReceipt, error) } // TrackExecutionDelivery retains the exact existing Core delivery through its diff --git a/internal/agentdaemon/gateway/cancellation_test.go b/services/core/internal/runtimegateway/cancellation_test.go similarity index 88% rename from internal/agentdaemon/gateway/cancellation_test.go rename to services/core/internal/runtimegateway/cancellation_test.go index ed201ebc1..a8e099f9d 100644 --- a/internal/agentdaemon/gateway/cancellation_test.go +++ b/services/core/internal/runtimegateway/cancellation_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -6,28 +6,28 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) type receiptStore struct { *fakeHeartbeatStore mu sync.Mutex - receipt device.ArchivedCancellationReceipt + receipt runtimedevice.ArchivedCancellationReceipt } -func (r *receiptStore) ArchivedCancellationReceipt(_ context.Context, id, hash string, runs []string) (device.ArchivedCancellationReceipt, error) { +func (r *receiptStore) ArchivedCancellationReceipt(_ context.Context, id, hash string, runs []string) (runtimedevice.ArchivedCancellationReceipt, error) { r.mu.Lock() defer r.mu.Unlock() if id != "device" || hash != "original-hash" { - return device.ArchivedCancellationReceipt{}, nil + return runtimedevice.ArchivedCancellationReceipt{}, nil } for _, run := range runs { if run == r.receipt.RunID { return r.receipt, nil } } - return device.ArchivedCancellationReceipt{}, nil + return runtimedevice.ArchivedCancellationReceipt{}, nil } func TestArchivedReceiptTracksDeliveryBeyondDoneAndRejectsNewWork(t *testing.T) { @@ -35,7 +35,7 @@ func TestArchivedReceiptTracksDeliveryBeyondDoneAndRejectsNewWork(t *testing.T) peer := NewSession(conn, "device", "", "", NewRegistry(), nil) defer peer.Close("test complete") peer.credentialHash = "original-hash" - receipt := device.ArchivedCancellationReceipt{RunID: "run", Deadline: time.Now().Add(time.Second)} + receipt := runtimedevice.ArchivedCancellationReceipt{RunID: "run", Deadline: time.Now().Add(time.Second)} peer.heartbeat = &receiptStore{fakeHeartbeatStore: newFakeHeartbeatStore(), receipt: receipt} if draining, err := peer.DrainArchivedCancellation(t.Context()); err != nil || draining { t.Fatal("unowned delivery got drain", draining, err) @@ -126,7 +126,7 @@ func TestArchivedReceiptDeadlineDoesNotRenew(t *testing.T) { peer := NewSession(newFakeConn(), "device", "", "", NewRegistry(), nil) defer peer.Close("test complete") peer.credentialHash = "original-hash" - receipt := device.ArchivedCancellationReceipt{RunID: "run", Deadline: time.Now().Add(100 * time.Millisecond)} + receipt := runtimedevice.ArchivedCancellationReceipt{RunID: "run", Deadline: time.Now().Add(100 * time.Millisecond)} peer.heartbeat = &receiptStore{fakeHeartbeatStore: newFakeHeartbeatStore(), receipt: receipt} release, err := peer.TrackExecutionDelivery("run") if err != nil { diff --git a/internal/agentdaemon/gateway/capabilities_test.go b/services/core/internal/runtimegateway/capabilities_test.go similarity index 93% rename from internal/agentdaemon/gateway/capabilities_test.go rename to services/core/internal/runtimegateway/capabilities_test.go index 78b5a3b23..da0a6af11 100644 --- a/internal/agentdaemon/gateway/capabilities_test.go +++ b/services/core/internal/runtimegateway/capabilities_test.go @@ -1,16 +1,16 @@ -package gateway +package runtimegateway import ( - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "reflect" "testing" ) func TestCapabilityProjectionCoversEveryField(t *testing.T) { declaration := prototest.Capabilities(proto.AgentKindCapabilities{}) - wireType, deviceType := reflect.TypeOf(declaration), reflect.TypeOf(device.KindCapabilities{}) + wireType, deviceType := reflect.TypeOf(declaration), reflect.TypeOf(runtimedevice.KindCapabilities{}) if wireType.NumField() != deviceType.NumField() { t.Fatal("wire and device capability inventories differ") } diff --git a/internal/agentdaemon/gateway/chunk_exchange.go b/services/core/internal/runtimegateway/chunk_exchange.go similarity index 96% rename from internal/agentdaemon/gateway/chunk_exchange.go rename to services/core/internal/runtimegateway/chunk_exchange.go index 5751ce474..05b50165a 100644 --- a/internal/agentdaemon/gateway/chunk_exchange.go +++ b/services/core/internal/runtimegateway/chunk_exchange.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/functions_test.go b/services/core/internal/runtimegateway/functions_test.go similarity index 97% rename from internal/agentdaemon/gateway/functions_test.go rename to services/core/internal/runtimegateway/functions_test.go index f4fca9933..e39a7fa83 100644 --- a/internal/agentdaemon/gateway/functions_test.go +++ b/services/core/internal/runtimegateway/functions_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" diff --git a/internal/agentdaemon/gateway/handler.go b/services/core/internal/runtimegateway/handler.go similarity index 80% rename from internal/agentdaemon/gateway/handler.go rename to services/core/internal/runtimegateway/handler.go index ca1b4ff81..a34782d40 100644 --- a/internal/agentdaemon/gateway/handler.go +++ b/services/core/internal/runtimegateway/handler.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -10,16 +10,16 @@ import ( "github.com/gorilla/websocket" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) // HeartbeatTouch is the persistence interface the gateway uses to // bump last_heartbeat_at / promote pending_pairing -> online when a // daemon connects. type HeartbeatTouch interface { - TouchRuntimeHeartbeat(ctx context.Context, runtimeID string) (device.HeartbeatStatus, error) - TouchAgentDaemonHeartbeat(ctx context.Context, input device.Heartbeat) (device.HeartbeatStatus, error) + TouchRuntimeHeartbeat(ctx context.Context, runtimeID string) (runtimedevice.HeartbeatStatus, error) + TouchAgentDaemonHeartbeat(ctx context.Context, input runtimedevice.Heartbeat) (runtimedevice.HeartbeatStatus, error) MarkRuntimeOffline(ctx context.Context, runtimeID string) error } @@ -99,20 +99,6 @@ func NewHandler(cfg HandlerConfig) *Handler { // WS is the websocket upgrade entry point. Errors before the upgrade // return JSON 4xx; errors during the WS read loop fall to Session.Close // which closes subscriptions with a transport error, without execution events. -// -// @Summary Agent-daemon WebSocket upgrade -// @Description Long-lived duplex channel for daemon runtimes. Authenticated by the runner bearer in the HTTP Authorization header before upgrade. -// @Tags agent-daemon -// @ID agentDaemonWebsocket -// @Param device_id query string true "device id" -// @Param Authorization header string true "Bearer " -// @Param version query string true "daemon protocol version" -// @Success 101 {string} string "protocol switched" -// @Failure 400 {object} map[string]interface{} -// @Failure 401 {object} map[string]interface{} -// @Failure 403 {object} map[string]interface{} -// @Failure 426 {object} map[string]interface{} "incompatible protocol version" -// @Router /agent-daemon/ws [get] func (h *Handler) WS(w http.ResponseWriter, r *http.Request) { q := r.URL.Query() deviceID := q.Get("device_id") @@ -154,7 +140,7 @@ func (h *Handler) WS(w http.ResponseWriter, r *http.Request) { var lease *ownerLease if h.cfg.OwnerStore != nil { now := time.Now().UTC() - owner, ownerErr := h.cfg.OwnerStore.ClaimAgentDaemonDeviceOwner(r.Context(), device.ClaimOwner{ + owner, ownerErr := h.cfg.OwnerStore.ClaimAgentDaemonDeviceOwner(r.Context(), runtimedevice.ClaimOwner{ DeviceID: auth.DeviceID, WorkspaceID: auth.WorkspaceID, OwnerPodID: h.cfg.OwnerPodID, @@ -178,7 +164,7 @@ func (h *Handler) WS(w http.ResponseWriter, r *http.Request) { } sess := NewSessionWithOwner(conn, auth.DeviceID, auth.WorkspaceID, version, h.cfg.Registry, h.cfg.Log, lease) sess.heartbeat = h.cfg.Heartbeat - sess.credentialHash = device.HashCredential(token) + sess.credentialHash = runtimedevice.HashCredential(token) h.cfg.Log("agentdaemon gateway: ws upgrade ok, registering device_id=%s owner_pod=%s waiters=%d", auth.DeviceID, h.cfg.OwnerPodID, len(h.cfg.Registry.PendingWaiters(auth.DeviceID))) if prev := h.cfg.Registry.Register(sess); prev != nil { @@ -193,20 +179,6 @@ func (h *Handler) WS(w http.ResponseWriter, r *http.Request) { // the bearer in a separate HTTP step (rather than folded into the WS // upgrade) lets the daemon fail fast on credential problems with a // real HTTP status rather than the opaque WS close code. -// -// @Summary Bootstrap agent-daemon -// @Description Verifies the runner credential and returns the WebSocket URL, heartbeat interval, and protocol version the daemon should use. -// @Tags agent-daemon -// @ID bootstrapAgentDaemon -// @Accept json -// @Produce json -// @Param Authorization header string true "Bearer " -// @Param body body object{device_id=string} true "device_id" -// @Success 200 {object} map[string]interface{} "device_id, workspace_id, ws_url, heartbeat_seconds, protocol_version" -// @Failure 400 {object} map[string]interface{} -// @Failure 401 {object} map[string]interface{} -// @Failure 405 {object} map[string]interface{} -// @Router /agent-daemon/bootstrap [post] func (h *Handler) Bootstrap(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeAuthError(w, http.StatusMethodNotAllowed, "method_not_allowed", "") @@ -250,18 +222,6 @@ func (h *Handler) Bootstrap(w http.ResponseWriter, r *http.Request) { // DeviceStatus is a lightweight liveness probe the daemon hits before // the WS dial. -// -// @Summary Agent-daemon device status -// @Description Reports whether the caller's device has a live WebSocket registration and, when configured, the current owner-pod lease. -// @Tags agent-daemon -// @ID getAgentDaemonDeviceStatus -// @Produce json -// @Param Authorization header string true "Bearer " -// @Param device_id query string true "device id" -// @Success 200 {object} map[string]interface{} "device_id, online, owner" -// @Failure 400 {object} map[string]interface{} -// @Failure 401 {object} map[string]interface{} -// @Router /agent-daemon/device-status [get] func (h *Handler) DeviceStatus(w http.ResponseWriter, r *http.Request) { bearer := bearerFromAuthHeader(r) if bearer == "" { @@ -288,7 +248,7 @@ func (h *Handler) DeviceStatus(w http.ResponseWriter, r *http.Request) { if current, ok, ownerErr := h.cfg.OwnerStore.GetAgentDaemonDeviceOwner(r.Context(), auth.DeviceID); ownerErr != nil { h.cfg.Log("agentdaemon gateway: device-status owner lookup failed: %v", ownerErr) } else if ok { - leaseOnline := current.Status == device.OwnerStatusConnected && current.LeaseExpiresAt.After(time.Now().UTC()) + leaseOnline := current.Status == runtimedevice.OwnerStatusConnected && current.LeaseExpiresAt.After(time.Now().UTC()) online = online || leaseOnline owner = map[string]any{ "owner_pod_id": current.OwnerPodID, diff --git a/internal/agentdaemon/gateway/handler_test.go b/services/core/internal/runtimegateway/handler_test.go similarity index 91% rename from internal/agentdaemon/gateway/handler_test.go rename to services/core/internal/runtimegateway/handler_test.go index a9d9678c5..e2e03cd63 100644 --- a/internal/agentdaemon/gateway/handler_test.go +++ b/services/core/internal/runtimegateway/handler_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "net/http" @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/gorilla/websocket" ) @@ -30,9 +30,9 @@ func TestWebSocketRequiresAuthorizationBearer(t *testing.T) { registry := NewRegistry() handler := NewHandler(HandlerConfig{ Registry: registry, - Authenticator: NewAuthenticator(&stubRuntimeStore{ok: true, row: device.Credential{ + Authenticator: NewAuthenticator(&stubRuntimeStore{ok: true, row: runtimedevice.Credential{ ID: "device", WorkspaceID: "tenant", Type: RuntimeTypeAgentDaemon, - CredentialHash: device.HashCredential(credential), + CredentialHash: runtimedevice.HashCredential(credential), }}), }) server := httptest.NewServer(http.HandlerFunc(handler.WS)) diff --git a/internal/agentdaemon/gateway/mcp_bearer_fixture_linux_test.go b/services/core/internal/runtimegateway/mcp_bearer_fixture_linux_test.go similarity index 99% rename from internal/agentdaemon/gateway/mcp_bearer_fixture_linux_test.go rename to services/core/internal/runtimegateway/mcp_bearer_fixture_linux_test.go index 28ec63d09..025061545 100644 --- a/internal/agentdaemon/gateway/mcp_bearer_fixture_linux_test.go +++ b/services/core/internal/runtimegateway/mcp_bearer_fixture_linux_test.go @@ -1,6 +1,6 @@ //go:build linux -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/mcp_bearer_live_linux_test.go b/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go similarity index 96% rename from internal/agentdaemon/gateway/mcp_bearer_live_linux_test.go rename to services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go index 911769470..778e4032d 100644 --- a/internal/agentdaemon/gateway/mcp_bearer_live_linux_test.go +++ b/services/core/internal/runtimegateway/mcp_bearer_live_linux_test.go @@ -1,6 +1,6 @@ //go:build linux -package gateway +package runtimegateway import ( "bytes" @@ -13,8 +13,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/go-chi/chi/v5" "github.com/google/uuid" ) @@ -51,7 +51,7 @@ func TestLiveMCPBearerGatewayColdContinuation(t *testing.T) { }) id := uuid.NewString() registry := NewRegistry() - auth := NewAuthenticator(&stubRuntimeStore{ok: true, row: device.Credential{ID: id, WorkspaceID: uuid.NewString(), Type: RuntimeTypeAgentDaemon, CredentialHash: device.HashCredential(runner)}}) + auth := NewAuthenticator(&stubRuntimeStore{ok: true, row: runtimedevice.Credential{ID: id, WorkspaceID: uuid.NewString(), Type: RuntimeTypeAgentDaemon, CredentialHash: runtimedevice.HashCredential(runner)}}) router := chi.NewRouter() server := httptest.NewServer(router) t.Cleanup(server.Close) diff --git a/internal/agentdaemon/gateway/mcp_bearer_process_linux_test.go b/services/core/internal/runtimegateway/mcp_bearer_process_linux_test.go similarity index 99% rename from internal/agentdaemon/gateway/mcp_bearer_process_linux_test.go rename to services/core/internal/runtimegateway/mcp_bearer_process_linux_test.go index e9f1a2c86..d8d85d26e 100644 --- a/internal/agentdaemon/gateway/mcp_bearer_process_linux_test.go +++ b/services/core/internal/runtimegateway/mcp_bearer_process_linux_test.go @@ -1,6 +1,6 @@ //go:build linux -package gateway +package runtimegateway import ( "bytes" diff --git a/internal/agentdaemon/gateway/mcp_test.go b/services/core/internal/runtimegateway/mcp_test.go similarity index 98% rename from internal/agentdaemon/gateway/mcp_test.go rename to services/core/internal/runtimegateway/mcp_test.go index dbdf0f6d0..c78c9d6ee 100644 --- a/internal/agentdaemon/gateway/mcp_test.go +++ b/services/core/internal/runtimegateway/mcp_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "encoding/json" diff --git a/internal/agentdaemon/gateway/owner.go b/services/core/internal/runtimegateway/owner.go similarity index 53% rename from internal/agentdaemon/gateway/owner.go rename to services/core/internal/runtimegateway/owner.go index eb32b1ad7..9155c5347 100644 --- a/internal/agentdaemon/gateway/owner.go +++ b/services/core/internal/runtimegateway/owner.go @@ -1,10 +1,10 @@ -package gateway +package runtimegateway import ( "context" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) const defaultOwnerLeaseTTL = 90 * time.Second @@ -12,10 +12,10 @@ const defaultOwnerLeaseTTL = 90 * time.Second // DeviceOwnerStore is the DB-backed owner lease surface used by the // gateway. type DeviceOwnerStore interface { - ClaimAgentDaemonDeviceOwner(ctx context.Context, input device.ClaimOwner) (device.Owner, error) - RenewAgentDaemonDeviceOwner(ctx context.Context, input device.RenewOwner) (device.Owner, bool, error) - ReleaseAgentDaemonDeviceOwner(ctx context.Context, input device.ReleaseOwner) (bool, error) - GetAgentDaemonDeviceOwner(ctx context.Context, deviceID string) (device.Owner, bool, error) + ClaimAgentDaemonDeviceOwner(ctx context.Context, input runtimedevice.ClaimOwner) (runtimedevice.Owner, error) + RenewAgentDaemonDeviceOwner(ctx context.Context, input runtimedevice.RenewOwner) (runtimedevice.Owner, bool, error) + ReleaseAgentDaemonDeviceOwner(ctx context.Context, input runtimedevice.ReleaseOwner) (bool, error) + GetAgentDaemonDeviceOwner(ctx context.Context, deviceID string) (runtimedevice.Owner, bool, error) } type ownerLease struct { diff --git a/internal/agentdaemon/gateway/owner_test.go b/services/core/internal/runtimegateway/owner_test.go similarity index 79% rename from internal/agentdaemon/gateway/owner_test.go rename to services/core/internal/runtimegateway/owner_test.go index 60bc49c64..dc17a37b0 100644 --- a/internal/agentdaemon/gateway/owner_test.go +++ b/services/core/internal/runtimegateway/owner_test.go @@ -1,12 +1,12 @@ -package gateway +package runtimegateway import ( "context" "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) type fakeOwnerStore struct { @@ -17,17 +17,17 @@ type fakeOwnerStore struct { lastRenewGen int64 } -func (f *fakeOwnerStore) ClaimAgentDaemonDeviceOwner(context.Context, device.ClaimOwner) (device.Owner, error) { - return device.Owner{}, nil +func (f *fakeOwnerStore) ClaimAgentDaemonDeviceOwner(context.Context, runtimedevice.ClaimOwner) (runtimedevice.Owner, error) { + return runtimedevice.Owner{}, nil } -func (f *fakeOwnerStore) RenewAgentDaemonDeviceOwner(_ context.Context, in device.RenewOwner) (device.Owner, bool, error) { +func (f *fakeOwnerStore) RenewAgentDaemonDeviceOwner(_ context.Context, in runtimedevice.RenewOwner) (runtimedevice.Owner, bool, error) { f.renewCalls++ f.lastRenewGen = in.Generation - return device.Owner{}, f.renewOK, nil + return runtimedevice.Owner{}, f.renewOK, nil } -func (f *fakeOwnerStore) ReleaseAgentDaemonDeviceOwner(context.Context, device.ReleaseOwner) (bool, error) { +func (f *fakeOwnerStore) ReleaseAgentDaemonDeviceOwner(context.Context, runtimedevice.ReleaseOwner) (bool, error) { f.releaseCalls++ if f.releaseCh != nil { select { @@ -39,8 +39,8 @@ func (f *fakeOwnerStore) ReleaseAgentDaemonDeviceOwner(context.Context, device.R return true, nil } -func (f *fakeOwnerStore) GetAgentDaemonDeviceOwner(context.Context, string) (device.Owner, bool, error) { - return device.Owner{}, false, nil +func (f *fakeOwnerStore) GetAgentDaemonDeviceOwner(context.Context, string) (runtimedevice.Owner, bool, error) { + return runtimedevice.Owner{}, false, nil } func TestSessionOwnerLeaseLostClosesStaleConnection(t *testing.T) { diff --git a/internal/agentdaemon/gateway/preparation.go b/services/core/internal/runtimegateway/preparation.go similarity index 99% rename from internal/agentdaemon/gateway/preparation.go rename to services/core/internal/runtimegateway/preparation.go index 286e5759c..31820f5f4 100644 --- a/internal/agentdaemon/gateway/preparation.go +++ b/services/core/internal/runtimegateway/preparation.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "errors" diff --git a/internal/agentdaemon/gateway/preparation_test.go b/services/core/internal/runtimegateway/preparation_test.go similarity index 99% rename from internal/agentdaemon/gateway/preparation_test.go rename to services/core/internal/runtimegateway/preparation_test.go index e9bdeef28..b4383a498 100644 --- a/internal/agentdaemon/gateway/preparation_test.go +++ b/services/core/internal/runtimegateway/preparation_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "errors" diff --git a/internal/agentdaemon/gateway/registry.go b/services/core/internal/runtimegateway/registry.go similarity index 99% rename from internal/agentdaemon/gateway/registry.go rename to services/core/internal/runtimegateway/registry.go index ba6711c23..74de0139d 100644 --- a/internal/agentdaemon/gateway/registry.go +++ b/services/core/internal/runtimegateway/registry.go @@ -5,7 +5,7 @@ // // The package deliberately does NOT depend on the connector // implementation — the connector imports it, not the other way around. -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/registry_test.go b/services/core/internal/runtimegateway/registry_test.go similarity index 99% rename from internal/agentdaemon/gateway/registry_test.go rename to services/core/internal/runtimegateway/registry_test.go index 4ac2456f1..0031d8470 100644 --- a/internal/agentdaemon/gateway/registry_test.go +++ b/services/core/internal/runtimegateway/registry_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/routes.go b/services/core/internal/runtimegateway/routes.go similarity index 97% rename from internal/agentdaemon/gateway/routes.go rename to services/core/internal/runtimegateway/routes.go index a786a291b..c7bf72429 100644 --- a/internal/agentdaemon/gateway/routes.go +++ b/services/core/internal/runtimegateway/routes.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "github.com/go-chi/chi/v5" diff --git a/internal/agentdaemon/gateway/runtime_prepare.go b/services/core/internal/runtimegateway/runtime_prepare.go similarity index 99% rename from internal/agentdaemon/gateway/runtime_prepare.go rename to services/core/internal/runtimegateway/runtime_prepare.go index 8056a87be..77e6493f9 100644 --- a/internal/agentdaemon/gateway/runtime_prepare.go +++ b/services/core/internal/runtimegateway/runtime_prepare.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/runtime_prepare_test.go b/services/core/internal/runtimegateway/runtime_prepare_test.go similarity index 99% rename from internal/agentdaemon/gateway/runtime_prepare_test.go rename to services/core/internal/runtimegateway/runtime_prepare_test.go index 1955f34d7..b070cbb50 100644 --- a/internal/agentdaemon/gateway/runtime_prepare_test.go +++ b/services/core/internal/runtimegateway/runtime_prepare_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "bytes" diff --git a/internal/agentdaemon/gateway/session.go b/services/core/internal/runtimegateway/session.go similarity index 94% rename from internal/agentdaemon/gateway/session.go rename to services/core/internal/runtimegateway/session.go index 118d8fec1..d2fd77d35 100644 --- a/internal/agentdaemon/gateway/session.go +++ b/services/core/internal/runtimegateway/session.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -12,9 +12,9 @@ import ( "github.com/gorilla/websocket" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" obslog "github.com/MiniMax-AI/OpenAgentCore/internal/obs/log" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) // Tunables. Package-level so tests can override via small helpers @@ -99,7 +99,7 @@ type Session struct { // dispatching prompt_request so unsupported engines fail on the server. kindsMu sync.RWMutex kindsSeen bool - supportedKinds []device.SupportedAgentKind + supportedKinds []runtimedevice.SupportedAgentKind // Subscribers keyed by runID. The read loop only sends on these // channels; Unsubscribe is the only place that closes them. @@ -130,7 +130,7 @@ type Session struct { // collapse into one. receiptMu sync.Mutex deliveries map[string]struct{} - receiptDrain device.ArchivedCancellationReceipt + receiptDrain runtimedevice.ArchivedCancellationReceipt receiptTimer *time.Timer closeOnce sync.Once @@ -205,29 +205,29 @@ func (s *Session) LastSeen() time.Time { // AgentKindStatus returns the latest advertised descriptor for kind. // found=false means the daemon has not advertised that kind; snapshotKnown // distinguishes "no heartbeat yet" from "heartbeat arrived and omitted it". -func (s *Session) AgentKindStatus(kind string) (info device.SupportedAgentKind, found bool, snapshotKnown bool) { +func (s *Session) AgentKindStatus(kind string) (info runtimedevice.SupportedAgentKind, found bool, snapshotKnown bool) { kind = strings.TrimSpace(kind) if kind == "" { - return device.SupportedAgentKind{}, false, false + return runtimedevice.SupportedAgentKind{}, false, false } s.kindsMu.RLock() seen := s.kindsSeen - kinds := make([]device.SupportedAgentKind, len(s.supportedKinds)) + kinds := make([]runtimedevice.SupportedAgentKind, len(s.supportedKinds)) copy(kinds, s.supportedKinds) s.kindsMu.RUnlock() if !seen { - return device.SupportedAgentKind{}, false, false + return runtimedevice.SupportedAgentKind{}, false, false } for _, candidate := range kinds { if candidate.Kind == kind { return candidate, true, true } } - return device.SupportedAgentKind{}, false, true + return runtimedevice.SupportedAgentKind{}, false, true } -func (s *Session) setSupportedAgentKinds(kinds []device.SupportedAgentKind) { - copyKinds := make([]device.SupportedAgentKind, len(kinds)) +func (s *Session) setSupportedAgentKinds(kinds []runtimedevice.SupportedAgentKind) { + copyKinds := make([]runtimedevice.SupportedAgentKind, len(kinds)) copy(copyKinds, kinds) s.kindsMu.Lock() s.kindsSeen = true @@ -416,7 +416,7 @@ func (s *Session) renewOwnerLease() bool { now := time.Now().UTC() ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - _, ok, err := s.owner.store.RenewAgentDaemonDeviceOwner(ctx, device.RenewOwner{ + _, ok, err := s.owner.store.RenewAgentDaemonDeviceOwner(ctx, runtimedevice.RenewOwner{ DeviceID: s.owner.deviceID, OwnerPodID: s.owner.ownerPodID, Generation: s.owner.generation, @@ -442,7 +442,7 @@ func (s *Session) releaseOwnerLease() { } ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - if _, err := s.owner.store.ReleaseAgentDaemonDeviceOwner(ctx, device.ReleaseOwner{ + if _, err := s.owner.store.ReleaseAgentDaemonDeviceOwner(ctx, runtimedevice.ReleaseOwner{ DeviceID: s.owner.deviceID, OwnerPodID: s.owner.ownerPodID, Generation: s.owner.generation, @@ -478,7 +478,7 @@ func (s *Session) handleHeartbeat(env proto.Envelope) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - status, err := s.heartbeat.TouchAgentDaemonHeartbeat(ctx, device.Heartbeat{ + status, err := s.heartbeat.TouchAgentDaemonHeartbeat(ctx, runtimedevice.Heartbeat{ RuntimeID: s.DeviceID, CredentialHash: s.credentialHash, DaemonVersion: p.DaemonVersion, @@ -504,14 +504,14 @@ func (s *Session) handleHeartbeat(env proto.Envelope) { } } -func deviceKindsFromHeartbeat(p proto.HeartbeatPayload) []device.SupportedAgentKind { - out := make([]device.SupportedAgentKind, 0, len(p.SupportedAgentKinds)) +func deviceKindsFromHeartbeat(p proto.HeartbeatPayload) []runtimedevice.SupportedAgentKind { + out := make([]runtimedevice.SupportedAgentKind, 0, len(p.SupportedAgentKinds)) for _, info := range p.SupportedAgentKinds { - out = append(out, device.SupportedAgentKind{ + out = append(out, runtimedevice.SupportedAgentKind{ Kind: info.Kind, Available: info.Available, Version: info.Version, - Capabilities: device.KindCapabilities{ + Capabilities: runtimedevice.KindCapabilities{ Streaming: info.Capabilities.Streaming.IsSupported(), Permissions: info.Capabilities.Permissions.IsSupported(), Usage: info.Capabilities.Usage.IsSupported(), diff --git a/internal/agentdaemon/gateway/session_test.go b/services/core/internal/runtimegateway/session_test.go similarity index 95% rename from internal/agentdaemon/gateway/session_test.go rename to services/core/internal/runtimegateway/session_test.go index b7834bfd6..fc1422ccf 100644 --- a/internal/agentdaemon/gateway/session_test.go +++ b/services/core/internal/runtimegateway/session_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) // fakeConn is the WSConn implementation used by session + registry @@ -105,23 +105,23 @@ func (c *fakeConn) Writes() [][]byte { type fakeHeartbeatStore struct { mu sync.Mutex - daemonCh chan device.Heartbeat - daemon []device.Heartbeat + daemonCh chan runtimedevice.Heartbeat + daemon []runtimedevice.Heartbeat runtime []string } func newFakeHeartbeatStore() *fakeHeartbeatStore { - return &fakeHeartbeatStore{daemonCh: make(chan device.Heartbeat, 4)} + return &fakeHeartbeatStore{daemonCh: make(chan runtimedevice.Heartbeat, 4)} } -func (f *fakeHeartbeatStore) TouchRuntimeHeartbeat(_ context.Context, runtimeID string) (device.HeartbeatStatus, error) { +func (f *fakeHeartbeatStore) TouchRuntimeHeartbeat(_ context.Context, runtimeID string) (runtimedevice.HeartbeatStatus, error) { f.mu.Lock() f.runtime = append(f.runtime, runtimeID) f.mu.Unlock() - return device.HeartbeatStatus{Liveness: "online"}, nil + return runtimedevice.HeartbeatStatus{Liveness: "online"}, nil } -func (f *fakeHeartbeatStore) TouchAgentDaemonHeartbeat(_ context.Context, input device.Heartbeat) (device.HeartbeatStatus, error) { +func (f *fakeHeartbeatStore) TouchAgentDaemonHeartbeat(_ context.Context, input runtimedevice.Heartbeat) (runtimedevice.HeartbeatStatus, error) { f.mu.Lock() f.daemon = append(f.daemon, input) f.mu.Unlock() @@ -129,14 +129,14 @@ func (f *fakeHeartbeatStore) TouchAgentDaemonHeartbeat(_ context.Context, input case f.daemonCh <- input: default: } - return device.HeartbeatStatus{Liveness: "online"}, nil + return runtimedevice.HeartbeatStatus{Liveness: "online"}, nil } func (f *fakeHeartbeatStore) MarkRuntimeOffline(_ context.Context, _ string) error { return nil } -func (f *fakeHeartbeatStore) waitDaemonHeartbeat(t *testing.T) device.Heartbeat { +func (f *fakeHeartbeatStore) waitDaemonHeartbeat(t *testing.T) runtimedevice.Heartbeat { t.Helper() select { case input := <-f.daemonCh: @@ -144,7 +144,7 @@ func (f *fakeHeartbeatStore) waitDaemonHeartbeat(t *testing.T) device.Heartbeat case <-time.After(2 * time.Second): t.Fatal("daemon heartbeat was not persisted") } - return device.Heartbeat{} + return runtimedevice.Heartbeat{} } // ---- registry tests ------------------------------------------------- @@ -416,7 +416,7 @@ func TestSession_HeartbeatPersistsSupportedAgentKinds(t *testing.T) { if len(got.SupportedAgentKinds) != 3 { t.Fatalf("SupportedAgentKinds len = %d, want 3: %#v", len(got.SupportedAgentKinds), got.SupportedAgentKinds) } - byKind := map[string]device.SupportedAgentKind{} + byKind := map[string]runtimedevice.SupportedAgentKind{} for _, info := range got.SupportedAgentKinds { byKind[info.Kind] = info } diff --git a/internal/agentdaemon/gateway/subscription.go b/services/core/internal/runtimegateway/subscription.go similarity index 98% rename from internal/agentdaemon/gateway/subscription.go rename to services/core/internal/runtimegateway/subscription.go index dd5ac5ffe..26864a24b 100644 --- a/internal/agentdaemon/gateway/subscription.go +++ b/services/core/internal/runtimegateway/subscription.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "errors" diff --git a/internal/agentdaemon/gateway/subscription_test.go b/services/core/internal/runtimegateway/subscription_test.go similarity index 98% rename from internal/agentdaemon/gateway/subscription_test.go rename to services/core/internal/runtimegateway/subscription_test.go index 972443cad..1fbece704 100644 --- a/internal/agentdaemon/gateway/subscription_test.go +++ b/services/core/internal/runtimegateway/subscription_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "errors" diff --git a/internal/agentdaemon/gateway/suspension.go b/services/core/internal/runtimegateway/suspension.go similarity index 99% rename from internal/agentdaemon/gateway/suspension.go rename to services/core/internal/runtimegateway/suspension.go index 7474673a9..a62aaaf1c 100644 --- a/internal/agentdaemon/gateway/suspension.go +++ b/services/core/internal/runtimegateway/suspension.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/suspension_test.go b/services/core/internal/runtimegateway/suspension_test.go similarity index 99% rename from internal/agentdaemon/gateway/suspension_test.go rename to services/core/internal/runtimegateway/suspension_test.go index df49708bc..081d2332d 100644 --- a/internal/agentdaemon/gateway/suspension_test.go +++ b/services/core/internal/runtimegateway/suspension_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/workspace_directory_test.go b/services/core/internal/runtimegateway/workspace_directory_test.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_directory_test.go rename to services/core/internal/runtimegateway/workspace_directory_test.go index 7be0ee409..3f6ea3c0d 100644 --- a/internal/agentdaemon/gateway/workspace_directory_test.go +++ b/services/core/internal/runtimegateway/workspace_directory_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "encoding/json" diff --git a/internal/agentdaemon/gateway/workspace_export.go b/services/core/internal/runtimegateway/workspace_export.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_export.go rename to services/core/internal/runtimegateway/workspace_export.go index 7b8b373de..2b9549ff5 100644 --- a/internal/agentdaemon/gateway/workspace_export.go +++ b/services/core/internal/runtimegateway/workspace_export.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/workspace_export_test.go b/services/core/internal/runtimegateway/workspace_export_test.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_export_test.go rename to services/core/internal/runtimegateway/workspace_export_test.go index f769f7427..dc1b0bd4d 100644 --- a/internal/agentdaemon/gateway/workspace_export_test.go +++ b/services/core/internal/runtimegateway/workspace_export_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "bytes" diff --git a/internal/agentdaemon/gateway/workspace_read.go b/services/core/internal/runtimegateway/workspace_read.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_read.go rename to services/core/internal/runtimegateway/workspace_read.go index 739c61687..ca7159086 100644 --- a/internal/agentdaemon/gateway/workspace_read.go +++ b/services/core/internal/runtimegateway/workspace_read.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/workspace_read_test.go b/services/core/internal/runtimegateway/workspace_read_test.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_read_test.go rename to services/core/internal/runtimegateway/workspace_read_test.go index e212c5b97..f9df6a871 100644 --- a/internal/agentdaemon/gateway/workspace_read_test.go +++ b/services/core/internal/runtimegateway/workspace_read_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "bytes" diff --git a/internal/agentdaemon/gateway/workspace_write.go b/services/core/internal/runtimegateway/workspace_write.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_write.go rename to services/core/internal/runtimegateway/workspace_write.go index 050e0014d..a69223bbd 100644 --- a/internal/agentdaemon/gateway/workspace_write.go +++ b/services/core/internal/runtimegateway/workspace_write.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "context" diff --git a/internal/agentdaemon/gateway/workspace_write_test.go b/services/core/internal/runtimegateway/workspace_write_test.go similarity index 99% rename from internal/agentdaemon/gateway/workspace_write_test.go rename to services/core/internal/runtimegateway/workspace_write_test.go index 2f63ab826..924566f94 100644 --- a/internal/agentdaemon/gateway/workspace_write_test.go +++ b/services/core/internal/runtimegateway/workspace_write_test.go @@ -1,4 +1,4 @@ -package gateway +package runtimegateway import ( "bytes" diff --git a/services/core/internal/sandbox/providers/configuration_flow_test.go b/services/core/internal/sandbox/providers/configuration_flow_test.go index a3cedd3e8..0642c206e 100644 --- a/services/core/internal/sandbox/providers/configuration_flow_test.go +++ b/services/core/internal/sandbox/providers/configuration_flow_test.go @@ -5,9 +5,9 @@ import ( "context" "database/sql" "encoding/json" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/providercontract" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/providers" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" @@ -133,7 +133,7 @@ func TestAdditionalConfigurationProviderUsesCommonAPIAndStore(t *testing.T) { if err = w.ClaimWebSandboxDeployment(t.Context(), installation); err != nil { t.Fatal(err) } - auth, err := api.NewDeploymentAuthenticator([]string{device.HashCredential("fixture-admin")}) + auth, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("fixture-admin")}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/admin_session_archive_test.go b/services/core/internal/store/admin_session_archive_test.go index 9f6137675..6770beb1a 100644 --- a/services/core/internal/store/admin_session_archive_test.go +++ b/services/core/internal/store/admin_session_archive_test.go @@ -8,8 +8,8 @@ import ( "reflect" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -50,7 +50,7 @@ func managedArchiveSession(t *testing.T, s *Store, input CreateSessionInput) (st func archiveAllocation(t *testing.T, w *Store, tenant string, session Session, installation string) RuntimeAllocation { t.Helper() - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -109,7 +109,7 @@ func TestManagedSessionArchiveUnallocatedAndGuards(t *testing.T) { if status, err := s.GetManagedSessionArchive(ctx, tenant, session.ID); err != nil || status != result { t.Fatal("status differs from committed archive", status, err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, device.HashCredential(uuid.NewString())); !errors.Is(err, ErrInvalidInput) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, runtimedevice.HashCredential(uuid.NewString())); !errors.Is(err, ErrInvalidInput) { t.Fatal("archived Environment allocated after archive", err) } if _, err := s.ReserveEnvironmentInput(t.Context(), tenant, session.ID, "later", []Input{{Kind: "message", Payload: json.RawMessage(`{"text":"later"}`)}}); !errors.Is(err, ErrEnvironmentUnavailable) { @@ -155,7 +155,7 @@ func TestManagedSessionArchiveRetainsHistoryAndSettledResources(t *testing.T) { if _, err := w.ReleaseRuntimeAllocation(t.Context(), owner); !errors.Is(err, ErrTurnConflict) { t.Fatal("archive discarded unknown Create ownership", err) } - replay, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, device.HashCredential(uuid.NewString())) + replay, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, runtimedevice.HashCredential(uuid.NewString())) if err != nil || !replay.Replayed || replay.ID != owner.ID || replay.DeviceID != owner.DeviceID || replay.State != "cleanup_pending" { t.Fatal("late provisioning retry replaced archived allocation", replay, err) } diff --git a/services/core/internal/store/admin_session_archive_worker_http_test.go b/services/core/internal/store/admin_session_archive_worker_http_test.go index 719832744..2f137749c 100644 --- a/services/core/internal/store/admin_session_archive_worker_http_test.go +++ b/services/core/internal/store/admin_session_archive_worker_http_test.go @@ -13,12 +13,12 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -47,7 +47,7 @@ func TestAdminSessionArchiveWorkerHTTPPostgres(t *testing.T) { }, func(_ context.Context, setup store.SandboxSetup) (execution.PreparedRuntimeDeployment, error) { return execution.PreparedRuntimeDeployment{Config: providerConfig(setup)}, nil }) - worker, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: configuration}) + worker, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: configuration}) if err != nil { t.Fatal(err) } @@ -90,7 +90,7 @@ func TestAdminSessionArchiveWorkerHTTPPostgres(t *testing.T) { if _, err := s.ArchiveManagedSession(ctx, project.TenantID, active.ID, 1); !errors.Is(err, store.ErrInvalidInput) { t.Fatal("fixture admission Store unexpectedly holds execution ownership", err) } - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential("archive-administrator")}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential("archive-administrator")}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/agent_execution_defaults_http_test.go b/services/core/internal/store/agent_execution_defaults_http_test.go index be6a5f807..77f7fa72e 100644 --- a/services/core/internal/store/agent_execution_defaults_http_test.go +++ b/services/core/internal/store/agent_execution_defaults_http_test.go @@ -9,9 +9,9 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -21,7 +21,7 @@ func TestAgentExecutionDefaultsPublicSnapshotAndPrecedence(t *testing.T) { cipher, _ := credentialcrypto.New(bytes.Repeat([]byte{19}, 32)) st := store.NewWithCredentialCipher(pool, cipher) tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "defaults-test", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "defaults-test", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/agents_delete_public_test.go b/services/core/internal/store/agents_delete_public_test.go index 4b5d9b622..fb8b2aad7 100644 --- a/services/core/internal/store/agents_delete_public_test.go +++ b/services/core/internal/store/agents_delete_public_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -22,8 +22,8 @@ func TestAgentDeletionOfficialClient(t *testing.T) { s, pool := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/agents_update_public_test.go b/services/core/internal/store/agents_update_public_test.go index 0a55d2aec..9424ca826 100644 --- a/services/core/internal/store/agents_update_public_test.go +++ b/services/core/internal/store/agents_update_public_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -22,8 +22,8 @@ func TestAgentUpdateOfficialClient(t *testing.T) { s, pool := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/archive_cancellation_test.go b/services/core/internal/store/archive_cancellation_test.go index 3dbb129f8..81b368585 100644 --- a/services/core/internal/store/archive_cancellation_test.go +++ b/services/core/internal/store/archive_cancellation_test.go @@ -13,12 +13,12 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/gorilla/websocket" @@ -61,7 +61,7 @@ func TestArchiveWaitingCancellationReceipts(t *testing.T) { t.Fatal(err) } secret := uuid.NewString() - owner, err := writer.ReserveRuntimeAllocation(t.Context(), project.TenantID, session.Environment.ID, installation, device.HashCredential(secret)) + owner, err := writer.ReserveRuntimeAllocation(t.Context(), project.TenantID, session.Environment.ID, installation, runtimedevice.HashCredential(secret)) if err != nil { t.Fatal(err) } @@ -101,7 +101,7 @@ func TestArchiveWaitingCancellationReceipts(t *testing.T) { capabilities := workerEnvironmentCapabilities() capabilities.FunctionTools = proto.CapabilitySupported h.write("", proto.TypeHeartbeat, proto.HeartbeatPayload{SupportedAgentKinds: []proto.SupportedAgentKind{{Kind: "codex", Available: true, Capabilities: capabilities}}}) - var peer *gateway.Session + var peer *runtimegateway.Session for deadline := time.Now().Add(3 * time.Second); ; { peer, err = registry.LookupDevice(owner.DeviceID) if err == nil { @@ -177,7 +177,7 @@ func TestArchiveWaitingCancellationReceipts(t *testing.T) { if err != nil || current.Status != store.TurnWaiting || current.CancelRequestedAt.IsZero() { t.Fatal("archive must request rather than invent cancellation", current, err) } - if _, err := gateway.NewAuthenticator(s).AuthenticateBearer(t.Context(), owner.DeviceID, secret); !errors.Is(err, gateway.ErrAuthUnknownDevice) { + if _, err := runtimegateway.NewAuthenticator(s).AuthenticateBearer(t.Context(), owner.DeviceID, secret); !errors.Is(err, runtimegateway.ErrAuthUnknownDevice) { t.Fatal("archive allowed renewed authority", err) } rejected, response, dialErr := websocket.DefaultDialer.Dial(u.String(), http.Header{"Authorization": {"Bearer " + secret}}) @@ -194,11 +194,11 @@ func TestArchiveWaitingCancellationReceipts(t *testing.T) { if err != nil || drain.RunID != "" { t.Fatal("unowned delivery got receipt permission", drain, err) } - drain, err = s.ArchivedCancellationReceipt(t.Context(), owner.DeviceID, device.HashCredential(secret), []string{input.TurnID}) + drain, err = s.ArchivedCancellationReceipt(t.Context(), owner.DeviceID, runtimedevice.HashCredential(secret), []string{input.TurnID}) if err != nil || (drain.RunID == input.TurnID) == strings.Contains(scenario, "revoke") { t.Fatal("archive revocation causality lost", drain, err) } - if drain.RunID != "" && !drain.Deadline.Equal(current.CancelRequestedAt.Add(device.ArchivedCancellationReceiptLimit)) { + if drain.RunID != "" && !drain.Deadline.Equal(current.CancelRequestedAt.Add(runtimedevice.ArchivedCancellationReceiptLimit)) { t.Fatal("archive renewed cancellation deadline") } // Explicitly observe cancel delivery before inducing transport loss. This @@ -211,7 +211,7 @@ func TestArchiveWaitingCancellationReceipts(t *testing.T) { t.Fatal("missing cancel delivery identity") } if scenario == "rotated" { - if _, err := pool.Exec(t.Context(), "UPDATE devices SET credential_hash=$2 WHERE id=$1", owner.DeviceID, device.HashCredential(uuid.NewString())); err != nil { + if _, err := pool.Exec(t.Context(), "UPDATE devices SET credential_hash=$2 WHERE id=$1", owner.DeviceID, runtimedevice.HashCredential(uuid.NewString())); err != nil { t.Fatal(err) } } diff --git a/services/core/internal/store/configuration_validation_public_test.go b/services/core/internal/store/configuration_validation_public_test.go index 110d6080e..ef82fe7a7 100644 --- a/services/core/internal/store/configuration_validation_public_test.go +++ b/services/core/internal/store/configuration_validation_public_test.go @@ -8,9 +8,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -28,8 +28,8 @@ func TestAgentConfigurationValidationRejectsWithoutWritesPostgres(t *testing.T) s := store.NewWithCredentialCipher(pool, cipher) owner, foreign, ownerTenant := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "config-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "config-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "config-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "config-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/creation_stream_settlement_public_test.go b/services/core/internal/store/creation_stream_settlement_public_test.go index 37e2e5f91..f0d236a50 100644 --- a/services/core/internal/store/creation_stream_settlement_public_test.go +++ b/services/core/internal/store/creation_stream_settlement_public_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -120,7 +120,7 @@ func (s sseLines) open(t *testing.T) { func TestCreationStreamPublicLifetimes(t *testing.T) { s, pool := store.NewModelTestStore(t) tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/credential_matrix_http_test.go b/services/core/internal/store/credential_matrix_http_test.go index 6f7c88824..a9e0ff94a 100644 --- a/services/core/internal/store/credential_matrix_http_test.go +++ b/services/core/internal/store/credential_matrix_http_test.go @@ -10,11 +10,11 @@ import ( "sync" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimeenrollment" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -28,7 +28,7 @@ func TestCredentialNamespaceMatrix(t *testing.T) { s.SetPublicURL("https://core.example") ctx := t.Context() coreKey := uuid.NewString() - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential(coreKey)}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(coreKey)}) if err != nil { t.Fatal(err) } @@ -43,7 +43,7 @@ func TestCredentialNamespaceMatrix(t *testing.T) { // The server composition: daemon transport beside the API handler. mux := http.NewServeMux() mux.Handle("/api/v1/agent-daemon/enroll", runtimeenrollment.EnrollmentHandler(s)) - mux.Handle("/api/v1/agent-daemon/connection", runtimeenrollment.ConnectionHandler(s, gateway.NewRegistry())) + mux.Handle("/api/v1/agent-daemon/connection", runtimeenrollment.ConnectionHandler(s, runtimegateway.NewRegistry())) mux.Handle("/", handler) server := api.CanonicalPaths(mux) call := func(method, path, token, body string) *httptest.ResponseRecorder { @@ -98,7 +98,7 @@ func TestCredentialNamespaceMatrix(t *testing.T) { }, func(_ context.Context, setup store.SandboxSetup) (execution.PreparedRuntimeDeployment, error) { return execution.PreparedRuntimeDeployment{Config: &execution.RuntimeProvider{InstallationID: setup.InstallationID, ProviderKind: setup.Provider, Mode: setup.Mode, AdmissionPaused: setup.AdmissionPaused, CoreURL: "https://core.example/api/v1", BackendFingerprint: setup.BackendFingerprint, Provider: provider}}, nil }) - worker, err := execution.StartWorker(ctx, &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: runtimes}) + worker, err := execution.StartWorker(ctx, &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: runtimes}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/deployment_model_providers_http_test.go b/services/core/internal/store/deployment_model_providers_http_test.go index bda363fce..116d57b67 100644 --- a/services/core/internal/store/deployment_model_providers_http_test.go +++ b/services/core/internal/store/deployment_model_providers_http_test.go @@ -11,11 +11,11 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/adminaudit" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -31,11 +31,11 @@ func TestDeploymentModelProvidersHTTP(t *testing.T) { cipher, _ := credentialcrypto.New(bytes.Repeat([]byte{53}, 32)) st := store.NewWithCredentialCipher(pool, cipher) tenant, projectKey, coreKey := uuid.NewString(), uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "defaults-http", TokenSHA256: device.HashCredential(projectKey), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "defaults-http", TokenSHA256: runtimedevice.HashCredential(projectKey), TenantID: tenant}}) if err != nil { t.Fatal(err) } - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential(coreKey)}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(coreKey)}) if err != nil { t.Fatal(err) } @@ -293,7 +293,7 @@ func TestNoneSessionRetryAfterDeploymentDefaultChanges(t *testing.T) { t.Fatal(err) } tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "none-retry", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "none-retry", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } @@ -359,7 +359,7 @@ func TestNoneSessionRetryAfterDeploymentDefaultChanges(t *testing.T) { func TestDeploymentProviderResolutionPairsRevisionDuringReplacement(t *testing.T) { st, pool := store.NewManagedTestStore(t) tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tuple-test", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tuple-test", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/device_bootstrap_binding_test.go b/services/core/internal/store/device_bootstrap_binding_test.go index af7d7983c..d91292750 100644 --- a/services/core/internal/store/device_bootstrap_binding_test.go +++ b/services/core/internal/store/device_bootstrap_binding_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/google/uuid" ) @@ -34,22 +34,22 @@ func TestDeviceCredentialCarriesPersistedAllocationNode(t *testing.T) { if err != nil { t.Fatal(err) } - allocation, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, deployment.InstallationID, device.HashCredential(bearer)) + allocation, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, deployment.InstallationID, runtimedevice.HashCredential(bearer)) if err != nil { t.Fatal(err) } - authenticator := gateway.NewAuthenticator(s) + authenticator := runtimegateway.NewAuthenticator(s) auth, err := authenticator.AuthenticateBearer(t.Context(), allocation.DeviceID, bearer) if err != nil || auth.RuntimeNodeID != nodeID { t.Fatalf("authenticated node=%s want=%s error=%v", auth.RuntimeNodeID, nodeID, err) } - if _, err := authenticator.AuthenticateBearer(t.Context(), allocation.DeviceID, "wrong-token"); !errors.Is(err, gateway.ErrAuthBadCredential) { + if _, err := authenticator.AuthenticateBearer(t.Context(), allocation.DeviceID, "wrong-token"); !errors.Is(err, runtimegateway.ErrAuthBadCredential) { t.Fatal("binding bypassed credential check", err) } if err := s.RevokeDevice(t.Context(), tenant, allocation.DeviceID); err != nil { t.Fatal(err) } - if _, err := authenticator.AuthenticateBearer(t.Context(), allocation.DeviceID, bearer); !errors.Is(err, gateway.ErrAuthUnknownDevice) { + if _, err := authenticator.AuthenticateBearer(t.Context(), allocation.DeviceID, bearer); !errors.Is(err, runtimegateway.ErrAuthUnknownDevice) { t.Fatal("allocation revived revoked credential", err) } }) @@ -59,12 +59,12 @@ func TestDeviceCredentialCarriesPersistedAllocationNode(t *testing.T) { func TestDeviceCredentialWithoutManagedNodeRetainsPublicRouteIdentity(t *testing.T) { s, _ := testStore(t) tenant := uuid.NewString() - ordinary, err := s.CreateDevice(t.Context(), tenant, "ordinary", device.HashCredential("ordinary-token")) + ordinary, err := s.CreateDevice(t.Context(), tenant, "ordinary", runtimedevice.HashCredential("ordinary-token")) if err != nil { t.Fatal(err) } _, environment := localEnvironment(t, s, tenant) - allocation, err := executionLease(t, s).Store().ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), device.HashCredential("allocation-token")) + allocation, err := executionLease(t, s).Store().ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), runtimedevice.HashCredential("allocation-token")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/devices.go b/services/core/internal/store/devices.go index f84b4e3a4..66b780d64 100644 --- a/services/core/internal/store/devices.go +++ b/services/core/internal/store/devices.go @@ -11,9 +11,9 @@ import ( "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/db/sqlc" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" ) var ErrDeviceBindingConflict = errors.New("session is already bound to a different device") @@ -61,20 +61,20 @@ func newDeviceParams(tenant pgtype.UUID, name, credentialHash string) (sqlc.Crea // GetDeviceCredential is used only by the shared gateway's credential verifier. // The standalone service does not assign a product WorkspaceID. -func (s *Store) GetDeviceCredential(ctx context.Context, deviceID string) (device.Credential, bool, error) { +func (s *Store) GetDeviceCredential(ctx context.Context, deviceID string) (runtimedevice.Credential, bool, error) { id, err := parseID(deviceID) if err != nil { - return device.Credential{}, false, nil + return runtimedevice.Credential{}, false, nil } row, err := s.queries.GetDeviceCredential(ctx, id) if errors.Is(err, pgx.ErrNoRows) { - return device.Credential{}, false, nil + return runtimedevice.Credential{}, false, nil } if err != nil { - return device.Credential{}, false, err + return runtimedevice.Credential{}, false, err } - return device.Credential{ID: uuid.UUID(row.ID.Bytes).String(), Name: row.Name, - Type: gateway.RuntimeTypeAgentDaemon, CredentialHash: row.CredentialHash, RuntimeNodeID: row.RuntimeNodeID, RuntimeAllocationID: row.RuntimeAllocationID}, true, nil + return runtimedevice.Credential{ID: uuid.UUID(row.ID.Bytes).String(), Name: row.Name, + Type: runtimegateway.RuntimeTypeAgentDaemon, CredentialHash: row.CredentialHash, RuntimeNodeID: row.RuntimeNodeID, RuntimeAllocationID: row.RuntimeAllocationID}, true, nil } func (s *Store) RevokeDevice(ctx context.Context, tenantID, deviceID string) error { @@ -178,24 +178,24 @@ func deviceLookup(tenantID, id string) (sqlc.GetDeviceParams, error) { return p, err } -func (s *Store) TouchRuntimeHeartbeat(ctx context.Context, deviceID string) (device.HeartbeatStatus, error) { +func (s *Store) TouchRuntimeHeartbeat(ctx context.Context, deviceID string) (runtimedevice.HeartbeatStatus, error) { id, err := parseID(deviceID) if err != nil { - return device.HeartbeatStatus{}, err + return runtimedevice.HeartbeatStatus{}, err } n, err := s.queries.TouchDevice(ctx, id) - return device.HeartbeatStatus{Liveness: "online", Deleted: n == 0}, err + return runtimedevice.HeartbeatStatus{Liveness: "online", Deleted: n == 0}, err } -func (s *Store) TouchAgentDaemonHeartbeat(ctx context.Context, heartbeat device.Heartbeat) (device.HeartbeatStatus, error) { +func (s *Store) TouchAgentDaemonHeartbeat(ctx context.Context, heartbeat runtimedevice.Heartbeat) (runtimedevice.HeartbeatStatus, error) { id, err := parseID(heartbeat.RuntimeID) if err != nil { - return device.HeartbeatStatus{}, err + return runtimedevice.HeartbeatStatus{}, err } n, err := s.queries.TouchAuthenticatedDevice(ctx, sqlc.TouchAuthenticatedDeviceParams{ ID: id, CredentialHash: heartbeat.CredentialHash, }) - return device.HeartbeatStatus{Liveness: "online", Deleted: n == 0}, err + return runtimedevice.HeartbeatStatus{Liveness: "online", Deleted: n == 0}, err } // Live connectivity belongs to the gateway Registry. Only last-seen time is diff --git a/services/core/internal/store/devices_test.go b/services/core/internal/store/devices_test.go index cd48b13f0..45df558bf 100644 --- a/services/core/internal/store/devices_test.go +++ b/services/core/internal/store/devices_test.go @@ -15,16 +15,16 @@ import ( "github.com/google/uuid" "github.com/gorilla/websocket" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" ) func registerTestDevice(t *testing.T, s *Store, tenant string) (ExecutionDevice, string) { t.Helper() secret := uuid.NewString() + uuid.NewString() - d, err := s.CreateDevice(context.Background(), tenant, "isolated executor", device.HashCredential(secret)) + d, err := s.CreateDevice(context.Background(), tenant, "isolated executor", runtimedevice.HashCredential(secret)) if err != nil { t.Fatal(err) } @@ -177,13 +177,13 @@ func TestStandaloneGatewayUsesExecutionCredentials(t *testing.T) { _ = second.SetReadDeadline(time.Now().Add(2 * time.Second)) for { if _, _, err := second.ReadMessage(); err != nil { - if !websocket.IsCloseError(err, gateway.CloseRuntimeDeleted) { + if !websocket.IsCloseError(err, runtimegateway.CloseRuntimeDeleted) { t.Fatalf("revocation did not close connection: %v", err) } break } } - if _, err := gateway.NewAuthenticator(s).AuthenticateBearer(ctx, a.ID, secret); !errors.Is(err, gateway.ErrAuthUnknownDevice) { + if _, err := runtimegateway.NewAuthenticator(s).AuthenticateBearer(ctx, a.ID, secret); !errors.Is(err, runtimegateway.ErrAuthUnknownDevice) { t.Fatalf("revoked credential survived: %v", err) } } diff --git a/services/core/internal/store/dispatch_test.go b/services/core/internal/store/dispatch_test.go index cfc76942f..57f72c3b2 100644 --- a/services/core/internal/store/dispatch_test.go +++ b/services/core/internal/store/dispatch_test.go @@ -11,12 +11,12 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtime" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/gorilla/websocket" @@ -32,7 +32,7 @@ type dispatchHarness struct { session store.Session device store.ExecutionDevice conn *websocket.Conn - registry *gateway.Registry + registry *runtimegateway.Registry url string credential string environments map[string]*dispatchHarness @@ -69,9 +69,9 @@ func newDispatchHarnessForSession(t *testing.T, configuration []byte, local bool if getErr != nil { t.Fatal(getErr) } - h.device, err = s.CreateEnvironmentDevice(ctx, h.tenant, environment.ID, "local runtime", device.HashCredential(secret)) + h.device, err = s.CreateEnvironmentDevice(ctx, h.tenant, environment.ID, "local runtime", runtimedevice.HashCredential(secret)) } else { - h.device, err = s.CreateDevice(ctx, h.tenant, "isolated executor", device.HashCredential(secret)) + h.device, err = s.CreateDevice(ctx, h.tenant, "isolated executor", runtimedevice.HashCredential(secret)) } if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/environment_claim_worker_test.go b/services/core/internal/store/environment_claim_worker_test.go index 560af0cec..f9ab22c5c 100644 --- a/services/core/internal/store/environment_claim_worker_test.go +++ b/services/core/internal/store/environment_claim_worker_test.go @@ -6,8 +6,8 @@ import ( "errors" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -44,7 +44,7 @@ func TestWorkerReconcilesEnvironmentPromotionBeforeStart(t *testing.T) { t.Fatal(err) } awaitRelease() - restarted, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry()}) + restarted, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry()}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/environment_connection_worker_test.go b/services/core/internal/store/environment_connection_worker_test.go index 0d8073f1d..f2c5f67b8 100644 --- a/services/core/internal/store/environment_connection_worker_test.go +++ b/services/core/internal/store/environment_connection_worker_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -39,7 +39,7 @@ func TestEnvironmentConnectionWorkerReconcilesAndReleasesLease(t *testing.T) { t.Fatal(err) } awaitRelease() - dispatcher := &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry()} + dispatcher := &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry()} worker, err := execution.StartWorker(t.Context(), dispatcher) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/environment_executor_command_test.go b/services/core/internal/store/environment_executor_command_test.go index 38db65917..1669ad1bf 100644 --- a/services/core/internal/store/environment_executor_command_test.go +++ b/services/core/internal/store/environment_executor_command_test.go @@ -7,7 +7,7 @@ import ( "os/exec" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -64,14 +64,14 @@ func TestEnvironmentExecutorOperatorCommand(t *testing.T) { if next == first { t.Fatal("rotation returned the same key") } - if _, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, device.HashCredential(first)); !errors.Is(err, store.ErrNotFound) { + if _, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, runtimedevice.HashCredential(first)); !errors.Is(err, store.ErrNotFound) { t.Fatal("old command credential retained authority", err) } - if owner, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, device.HashCredential(next)); err != nil || owner != tenant { + if owner, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, runtimedevice.HashCredential(next)); err != nil || owner != tenant { t.Fatal("rotated command credential failed", err) } command(tenant, true, "--revoke") - if _, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, device.HashCredential(next)); !errors.Is(err, store.ErrNotFound) { + if _, err := s.AuthenticateEnvironmentExecutor(t.Context(), environment.ID, runtimedevice.HashCredential(next)); !errors.Is(err, store.ErrNotFound) { t.Fatal("revoked command credential retained authority", err) } t.Log("built operator command issued before Session creation, rejected duplicate/foreign requests, rotated and revoked durable credentials") diff --git a/services/core/internal/store/environment_expiry_worker_test.go b/services/core/internal/store/environment_expiry_worker_test.go index 665370260..51b4cce57 100644 --- a/services/core/internal/store/environment_expiry_worker_test.go +++ b/services/core/internal/store/environment_expiry_worker_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" @@ -106,7 +106,7 @@ func TestWorkerEnvironmentExpiryWithoutDevicesAndAfterRestart(t *testing.T) { dueTenant, due := newEnvironmentExpiryReservation(t, s) futureTenant, future := newEnvironmentExpiryReservation(t, s) makeEnvironmentExpiryDue(t, pool, &due) - d := &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry()} + d := &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry()} _, stop := startEnvironmentExpiryWorker(t, d) waitEnvironmentExpiry(t, s, dueTenant, due) got, err := s.GetEnvironmentInputReservation(t.Context(), futureTenant, future.SessionID, future.ID) diff --git a/services/core/internal/store/environment_file_write_semantics_public_test.go b/services/core/internal/store/environment_file_write_semantics_public_test.go index a72db893d..14a9fbf48 100644 --- a/services/core/internal/store/environment_file_write_semantics_public_test.go +++ b/services/core/internal/store/environment_file_write_semantics_public_test.go @@ -12,9 +12,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -57,8 +57,8 @@ func TestEnvironmentFileCreateRejectionsLeaveNoReceiptOrConsumption(t *testing.T } token, other := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tenant-b", TokenSHA256: device.HashCredential(other), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tenant-b", TokenSHA256: runtimedevice.HashCredential(other), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/environment_file_writes_test.go b/services/core/internal/store/environment_file_writes_test.go index 10f7749d9..531acf625 100644 --- a/services/core/internal/store/environment_file_writes_test.go +++ b/services/core/internal/store/environment_file_writes_test.go @@ -6,7 +6,7 @@ import ( "sync" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -25,7 +25,7 @@ func newFileWriteFixture(t *testing.T) fileWriteFixture { lease := executionLease(t, s) tenant := uuid.NewString() session, env := localEnvironment(t, s, tenant) - host, err := s.CreateEnvironmentDevice(t.Context(), tenant, env.ID, "file owner", device.HashCredential(uuid.NewString())) + host, err := s.CreateEnvironmentDevice(t.Context(), tenant, env.ID, "file owner", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/environment_initial_public_test.go b/services/core/internal/store/environment_initial_public_test.go index 61391d60b..34108ba43 100644 --- a/services/core/internal/store/environment_initial_public_test.go +++ b/services/core/internal/store/environment_initial_public_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -25,8 +25,8 @@ func TestEnvironmentInitialFailureOfficialClient(t *testing.T) { s, pool := store.NewTestStore(t) tenant, token, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: "other-project", SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: "other-project", SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/environment_initialization_test.go b/services/core/internal/store/environment_initialization_test.go index 770e6407f..046a557c1 100644 --- a/services/core/internal/store/environment_initialization_test.go +++ b/services/core/internal/store/environment_initialization_test.go @@ -5,11 +5,11 @@ import ( "context" "encoding/json" "errors" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/google/uuid" "net/http" @@ -70,12 +70,12 @@ func TestUserManagedPreparationUsesAuthenticatedRuntimeWithoutAllocation(t *test if err != nil { t.Fatal(err) } - enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, device.HashCredential(key.Token)) + enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, runtimedevice.HashCredential(key.Token)) if err != nil { t.Fatal(err) } - registry := gateway.NewRegistry() - handler := gateway.NewHandler(gateway.HandlerConfig{Authenticator: gateway.NewAuthenticator(s), Registry: registry}) + registry := runtimegateway.NewRegistry() + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Authenticator: runtimegateway.NewAuthenticator(s), Registry: registry}) server := httptest.NewServer(http.HandlerFunc(handler.WS)) defer server.Close() worker, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: registry}) @@ -190,7 +190,7 @@ func TestEnvironmentInitializationRevocationBeforeClaim(t *testing.T) { if err != nil { t.Fatal(err) } - enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, device.HashCredential(key.Token)) + enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, runtimedevice.HashCredential(key.Token)) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/environment_mcp_public_test.go b/services/core/internal/store/environment_mcp_public_test.go index 001c49545..7019d29b0 100644 --- a/services/core/internal/store/environment_mcp_public_test.go +++ b/services/core/internal/store/environment_mcp_public_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -17,7 +17,7 @@ func TestPublicEnvironmentMCPUsesAttachedVaultSelection(t *testing.T) { for _, kind := range []string{"codex", "claude_sdk", "mcode"} { t.Run(kind, func(t *testing.T) { s, pool, tenant, vault, credential := selfHostedMCPAdmissionFixture(t) - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test", TenantID: tenant, TokenSHA256: device.HashCredential("test-token")}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test", TenantID: tenant, TokenSHA256: runtimedevice.HashCredential("test-token")}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/environment_retrieve_public_test.go b/services/core/internal/store/environment_retrieve_public_test.go index c3d7acbc0..c4e8a7419 100644 --- a/services/core/internal/store/environment_retrieve_public_test.go +++ b/services/core/internal/store/environment_retrieve_public_test.go @@ -11,9 +11,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -28,9 +28,9 @@ func TestEnvironmentRetrievalOfficialClient(t *testing.T) { principal := store.FixtureExecutorPrincipal(t, s, tenant) token, peer, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: principal.OrganizationID, ProjectID: tenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: principal.OrganizationID, ProjectID: tenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: device.HashCredential(peer), TenantID: tenant}, - {OrganizationID: principal.OrganizationID, ProjectID: foreignTenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: principal.OrganizationID, ProjectID: tenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: principal.OrganizationID, ProjectID: tenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: runtimedevice.HashCredential(peer), TenantID: tenant}, + {OrganizationID: principal.OrganizationID, ProjectID: foreignTenant, SubjectKind: principal.SubjectKind, SubjectID: principal.SubjectID, TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/environment_runtime_fixture_test.go b/services/core/internal/store/environment_runtime_fixture_test.go index 915d800b3..0d7df2277 100644 --- a/services/core/internal/store/environment_runtime_fixture_test.go +++ b/services/core/internal/store/environment_runtime_fixture_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/gorilla/websocket" @@ -24,7 +24,7 @@ func enrollFixtureSession(t *testing.T, s *store.Store, tenant string, session s if err != nil { t.Fatal(err) } - enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, device.HashCredential(key.Token)) + enrolled, err := s.EnrollRuntime(t.Context(), environment.ID, runtimedevice.HashCredential(key.Token)) if err != nil || enrolled.EnvironmentID != environment.ID || enrolled.SessionID != session.ID || enrolled.WorkspaceDirectory != "/workspace" { t.Fatalf("Runtime enrollment: %+v %v", enrolled, err) } diff --git a/services/core/internal/store/execution_lease_test.go b/services/core/internal/store/execution_lease_test.go index 975f66cb3..3cae83f10 100644 --- a/services/core/internal/store/execution_lease_test.go +++ b/services/core/internal/store/execution_lease_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -30,7 +30,7 @@ func TestExecutionLeaseLossFencesAllLifecycleWrites(t *testing.T) { tenant, active := newTurnSession(t, s) input := submitMessage(t, s, tenant, active.ID, "active") transition(t, writer, tenant, active.ID, input.TurnID, TurnQueued, TurnInProgress) - host, err := s.CreateDevice(t.Context(), tenant, "owner test", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(t.Context(), tenant, "owner test", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/file_resource_semantics_public_test.go b/services/core/internal/store/file_resource_semantics_public_test.go index 95fb493f8..1e8400f39 100644 --- a/services/core/internal/store/file_resource_semantics_public_test.go +++ b/services/core/internal/store/file_resource_semantics_public_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -29,8 +29,8 @@ func TestFileResourceSemanticsOfficialClientPostgres(t *testing.T) { } token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "resources-owner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "resources-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "resources-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "resources-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/function_images_native_test.go b/services/core/internal/store/function_images_native_test.go index ad8d07e84..c266a37a7 100644 --- a/services/core/internal/store/function_images_native_test.go +++ b/services/core/internal/store/function_images_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -62,8 +62,8 @@ func TestNativeFunctionImagePublicExecution(t *testing.T) { }() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/function_inputs_public_test.go b/services/core/internal/store/function_inputs_public_test.go index 95fb07450..daaaac39b 100644 --- a/services/core/internal/store/function_inputs_public_test.go +++ b/services/core/internal/store/function_inputs_public_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -46,7 +46,7 @@ func TestFunctionInputsOfficialClientAtomicAdmission(t *testing.T) { t.Fatal(err) } } - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/function_public_native_test.go b/services/core/internal/store/function_public_native_test.go index 39ca911ae..76bf743e3 100644 --- a/services/core/internal/store/function_public_native_test.go +++ b/services/core/internal/store/function_public_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -82,7 +82,7 @@ func nativePublicFunctionServer(t *testing.T, h *dispatchHarness, ctx context.Co } }) token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/function_state_public_test.go b/services/core/internal/store/function_state_public_test.go index d46a7081f..35b612617 100644 --- a/services/core/internal/store/function_state_public_test.go +++ b/services/core/internal/store/function_state_public_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -45,7 +45,7 @@ func TestFunctionStateOfficialClientReadsAndLiveEvents(t *testing.T) { } } record("first") - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/harness_onboarding_test.go b/services/core/internal/store/harness_onboarding_test.go index b91433481..89f647461 100644 --- a/services/core/internal/store/harness_onboarding_test.go +++ b/services/core/internal/store/harness_onboarding_test.go @@ -16,12 +16,12 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/engine/enginetest" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -65,7 +65,7 @@ func TestThirdHarnessPublicOnboarding(t *testing.T) { } }() token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/hosted_initialization_failure_public_test.go b/services/core/internal/store/hosted_initialization_failure_public_test.go index cec555980..9a98dc524 100644 --- a/services/core/internal/store/hosted_initialization_failure_public_test.go +++ b/services/core/internal/store/hosted_initialization_failure_public_test.go @@ -17,11 +17,11 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -64,7 +64,7 @@ type hostedFailureProvider struct { steps []string } -func (p *hostedFailureProvider) setRuntimeGateway(t *testing.T, endpoint string, registry *gateway.Registry) { +func (p *hostedFailureProvider) setRuntimeGateway(t *testing.T, endpoint string, registry *runtimegateway.Registry) { p.initializationPeer.setRuntimeGateway(t, endpoint, registry) p.apply = p.prepare } @@ -294,8 +294,8 @@ func TestHostedInitializationFailurePublicHTTP(t *testing.T) { t.Cleanup(func() { slog.SetDefault(previous) }) w, _ := managedWorkerMode(t, s, key, p, false, true) auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tenant-b", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "tenant-b", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/initial_files_http_test.go b/services/core/internal/store/initial_files_http_test.go index 4fc2ebd11..135149b7b 100644 --- a/services/core/internal/store/initial_files_http_test.go +++ b/services/core/internal/store/initial_files_http_test.go @@ -8,9 +8,9 @@ import ( "net/http/httptest" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -23,7 +23,7 @@ func TestInitialFilesHTTPInlineLimitsAndRetry(t *testing.T) { } s := store.NewWithCredentialCipher(pool, cipher) tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/input_conflicts_public_test.go b/services/core/internal/store/input_conflicts_public_test.go index e29375520..312927b5a 100644 --- a/services/core/internal/store/input_conflicts_public_test.go +++ b/services/core/internal/store/input_conflicts_public_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -42,8 +42,8 @@ func TestSessionInputConflictsAndResultTargetsPostgres(t *testing.T) { ctx := t.Context() tenant, owner, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "conflict-owner", TokenSHA256: device.HashCredential(owner), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "conflict-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "conflict-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "conflict-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/list_cursor_public_test.go b/services/core/internal/store/list_cursor_public_test.go index 4f763cdc4..cc4e7fd04 100644 --- a/services/core/internal/store/list_cursor_public_test.go +++ b/services/core/internal/store/list_cursor_public_test.go @@ -12,10 +12,10 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -93,7 +93,7 @@ func seedCursorFixture(t *testing.T, s *store.Store, writer *store.Store, client if err != nil { t.Fatal(err) } - host, err := s.CreateDevice(ctx, tenant, "cursor "+key, device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(ctx, tenant, "cursor "+key, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -226,8 +226,8 @@ func TestListCursorErrorsPostgres(t *testing.T) { owner, foreign := uuid.NewString(), uuid.NewString() ownerTenant, foreignTenant := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "cursor-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "cursor-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "cursor-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "cursor-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/list_query_public_test.go b/services/core/internal/store/list_query_public_test.go index 6dad9e663..2b8e43ed3 100644 --- a/services/core/internal/store/list_query_public_test.go +++ b/services/core/internal/store/list_query_public_test.go @@ -9,10 +9,10 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -30,8 +30,8 @@ func TestListQueryOfficialClientPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "query-owner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "query-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "query-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "query-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/local_environment_devices_test.go b/services/core/internal/store/local_environment_devices_test.go index 93d42d4b7..c4caad34d 100644 --- a/services/core/internal/store/local_environment_devices_test.go +++ b/services/core/internal/store/local_environment_devices_test.go @@ -6,7 +6,7 @@ import ( "sync" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -32,7 +32,7 @@ func TestEnvironmentDeviceAuthorityAndLifecycle(t *testing.T) { session, environment := localEnvironment(t, s, tenant) sibling, _ := localEnvironment(t, s, tenant) foreign, _ := localEnvironment(t, s, foreignTenant) - digest := device.HashCredential(uuid.NewString()) + digest := runtimedevice.HashCredential(uuid.NewString()) if _, err := s.CreateEnvironmentDevice(t.Context(), foreignTenant, environment.ID, "foreign", digest); !errors.Is(err, ErrNotFound) { t.Fatalf("foreign provisioning: %v", err) } @@ -79,7 +79,7 @@ func TestEnvironmentDeviceProvisioningHasOneWinner(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - _, err := s.CreateEnvironmentDevice(t.Context(), tenant, environment.ID, "runtime", device.HashCredential(uuid.NewString())) + _, err := s.CreateEnvironmentDevice(t.Context(), tenant, environment.ID, "runtime", runtimedevice.HashCredential(uuid.NewString())) results <- err }() } @@ -103,7 +103,7 @@ func TestEnvironmentDeviceProvisioningHasOneWinner(t *testing.T) { if err := s.RevokeDevice(t.Context(), tenant, bound.ID); err != nil { t.Fatal(err) } - if _, err := s.CreateEnvironmentDevice(t.Context(), tenant, environment.ID, "replacement", device.HashCredential(uuid.NewString())); !errors.Is(err, ErrDeviceBindingConflict) { + if _, err := s.CreateEnvironmentDevice(t.Context(), tenant, environment.ID, "replacement", runtimedevice.HashCredential(uuid.NewString())); !errors.Is(err, ErrDeviceBindingConflict) { t.Fatalf("silent placement replacement: %v", err) } } diff --git a/services/core/internal/store/mcode_public_native_test.go b/services/core/internal/store/mcode_public_native_test.go index f718522c3..e80be8249 100644 --- a/services/core/internal/store/mcode_public_native_test.go +++ b/services/core/internal/store/mcode_public_native_test.go @@ -11,9 +11,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -61,8 +61,8 @@ func TestNativeMCodePublicExecution(t *testing.T) { }() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/mcp_credential_selection_public_test.go b/services/core/internal/store/mcp_credential_selection_public_test.go index 95adbbe9e..385c9f356 100644 --- a/services/core/internal/store/mcp_credential_selection_public_test.go +++ b/services/core/internal/store/mcp_credential_selection_public_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -34,8 +34,8 @@ func TestMCPCredentialSelectionPublicPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) tenantA, tokenA, tokenB := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-a", TokenSHA256: device.HashCredential(tokenA), TenantID: tenantA}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-b", TokenSHA256: device.HashCredential(tokenB), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-a", TokenSHA256: runtimedevice.HashCredential(tokenA), TenantID: tenantA}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-b", TokenSHA256: runtimedevice.HashCredential(tokenB), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/message_images_native_test.go b/services/core/internal/store/message_images_native_test.go index a80806f47..ad3034831 100644 --- a/services/core/internal/store/message_images_native_test.go +++ b/services/core/internal/store/message_images_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -62,8 +62,8 @@ func TestNativeMessageImagePublicExecution(t *testing.T) { }() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/model_protocol_native_test.go b/services/core/internal/store/model_protocol_native_test.go index 3b01021be..714572761 100644 --- a/services/core/internal/store/model_protocol_native_test.go +++ b/services/core/internal/store/model_protocol_native_test.go @@ -12,9 +12,9 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -83,7 +83,7 @@ func TestNativeModelProtocolPublicExecution(t *testing.T) { } }() token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}}) if err != nil { t.Fatal("cannot create fixture authenticator") } diff --git a/services/core/internal/store/native_public_execution_test.go b/services/core/internal/store/native_public_execution_test.go index 2c80e7033..8b110a407 100644 --- a/services/core/internal/store/native_public_execution_test.go +++ b/services/core/internal/store/native_public_execution_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -39,7 +39,7 @@ func verifyNativePublicExecution(t *testing.T, h *dispatchHarness, parent contex } }() token, foreign := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/path_id_semantics_public_test.go b/services/core/internal/store/path_id_semantics_public_test.go index 44d44da4b..7978cfdb4 100644 --- a/services/core/internal/store/path_id_semantics_public_test.go +++ b/services/core/internal/store/path_id_semantics_public_test.go @@ -10,9 +10,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" @@ -95,8 +95,8 @@ func TestMalformedPathIDsMatchMissingPostgres(t *testing.T) { owner, foreign := uuid.NewString(), uuid.NewString() ownerTenant := uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "path-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "path-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "path-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "path-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/project_api_keys_http_test.go b/services/core/internal/store/project_api_keys_http_test.go index a0ac0c81d..91342f725 100644 --- a/services/core/internal/store/project_api_keys_http_test.go +++ b/services/core/internal/store/project_api_keys_http_test.go @@ -6,8 +6,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -19,7 +19,7 @@ func TestProjectAndSharedKeysHTTPManagement(t *testing.T) { if err != nil { t.Fatal(err) } - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential(adminToken)}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(adminToken)}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/remote_mcp_test.go b/services/core/internal/store/remote_mcp_test.go index fa0148db8..40fe921b1 100644 --- a/services/core/internal/store/remote_mcp_test.go +++ b/services/core/internal/store/remote_mcp_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" @@ -95,7 +95,7 @@ func selfHostedMCPAdmissionFixture(t *testing.T) (*store.Store, *pgxpool.Pool, s func selfHostedMCPAdmissionHandler(t *testing.T, s *store.Store, tenant string) http.Handler { t.Helper() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test", TenantID: tenant, TokenSHA256: device.HashCredential("test-token")}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test", TenantID: tenant, TokenSHA256: runtimedevice.HashCredential("test-token")}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/request_body_public_test.go b/services/core/internal/store/request_body_public_test.go index ea0791f25..a4b7fb696 100644 --- a/services/core/internal/store/request_body_public_test.go +++ b/services/core/internal/store/request_body_public_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -30,8 +30,8 @@ func TestRequestBodyGateRejectsWithoutWritesPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) owner, foreign, ownerTenant := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "body-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "body-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "body-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "body-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) @@ -171,7 +171,7 @@ func TestRequestBodyGateExcludedRoutesPostgres(t *testing.T) { } s := store.NewWithCredentialCipher(pool, cipher) token, tenant := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "excluded-owner", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "excluded-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_adoption_test.go b/services/core/internal/store/runtime_adoption_test.go index 9c57015d4..b6629fa1a 100644 --- a/services/core/internal/store/runtime_adoption_test.go +++ b/services/core/internal/store/runtime_adoption_test.go @@ -5,7 +5,7 @@ import ( "reflect" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -17,13 +17,13 @@ func legacyAdoptionFixture(t *testing.T) (*Store, *Store, RuntimeDeployment, Run deploymentConfigure(t, w, &d) tenant := uuid.NewString() _, e := localEnvironment(t, s, tenant) - a, err := w.ReserveRuntimeAllocation(t.Context(), tenant, e.ID, d.InstallationID, device.HashCredential("runtime")) + a, err := w.ReserveRuntimeAllocation(t.Context(), tenant, e.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } d.ProviderKind = "docker" d.LocalNodeID = uuid.NewString() - d.LocalCredentialSHA256 = device.HashCredential("node") + d.LocalCredentialSHA256 = runtimedevice.HashCredential("node") d.LocalMaxActive, d.LocalMaxRetained = 4, 16 return s, w, d, a } diff --git a/services/core/internal/store/runtime_allocations_test.go b/services/core/internal/store/runtime_allocations_test.go index f6b77b6df..eecc62bf6 100644 --- a/services/core/internal/store/runtime_allocations_test.go +++ b/services/core/internal/store/runtime_allocations_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -18,7 +18,7 @@ func TestRuntimeAllocationAtomicOwnershipAndRecovery(t *testing.T) { tenant, provider := uuid.NewString(), uuid.NewString() session, environment := localEnvironment(t, s, tenant) secret := uuid.NewString() - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, device.HashCredential(secret)) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, runtimedevice.HashCredential(secret)) if err != nil || owner.Replayed || owner.State != "creating" || owner.CreateSettled { t.Fatalf("reservation: %+v %v", owner, err) } @@ -26,10 +26,10 @@ func TestRuntimeAllocationAtomicOwnershipAndRecovery(t *testing.T) { if err != nil || bound.ID != owner.DeviceID || bound.EnvironmentID != environment.ID { t.Fatalf("binding not committed with allocation: %+v %v", bound, err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), uuid.NewString(), environment.ID, provider, device.HashCredential(secret)); !errors.Is(err, ErrNotFound) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), uuid.NewString(), environment.ID, provider, runtimedevice.HashCredential(secret)); !errors.Is(err, ErrNotFound) { t.Fatalf("foreign allocation accepted: %v", err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), device.HashCredential(secret)); !errors.Is(err, ErrIdempotencyConflict) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), runtimedevice.HashCredential(secret)); !errors.Is(err, ErrIdempotencyConflict) { t.Fatalf("provider target changed: %v", err) } if err := lease.Close(t.Context()); err != nil { @@ -40,12 +40,12 @@ func TestRuntimeAllocationAtomicOwnershipAndRecovery(t *testing.T) { } reopened, _ := testStore(t) next := executionLease(t, reopened).Store() - retry, err := next.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, device.HashCredential(uuid.NewString())) + retry, err := next.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, runtimedevice.HashCredential(uuid.NewString())) if err != nil || !retry.Replayed || retry.ID != owner.ID || retry.DeviceID != owner.DeviceID { t.Fatalf("restart replaced unknown allocation: %+v %v", retry, err) } credential, ok, err := s.GetDeviceCredential(t.Context(), owner.DeviceID) - if err != nil || !ok || credential.CredentialHash != device.HashCredential(secret) { + if err != nil || !ok || credential.CredentialHash != runtimedevice.HashCredential(secret) { t.Fatal("retry rewrote bootstrap credential") } if err := s.DeleteSession(t.Context(), tenant, session.ID); err != nil { @@ -106,7 +106,7 @@ func TestRuntimeAllocationOneWinnerAndRollback(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - value, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, device.HashCredential(uuid.NewString())) + value, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, provider, runtimedevice.HashCredential(uuid.NewString())) results <- value errs <- err }() @@ -142,7 +142,7 @@ func TestRuntimeAllocationOneWinnerAndRollback(t *testing.T) { t.Cleanup(func() { _, _ = pool.Exec(context.Background(), "ALTER TABLE runtime_allocations DROP CONSTRAINT "+constraint) }) - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, fail.ID, provider, device.HashCredential(uuid.NewString())); err == nil { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, fail.ID, provider, runtimedevice.HashCredential(uuid.NewString())); err == nil { t.Fatal("injected insert failure succeeded") } var count int @@ -156,7 +156,7 @@ func TestRuntimeAllocationExpiryAndRevocation(t *testing.T) { w := executionLease(t, s).Store() tenant := uuid.NewString() _, environment := localEnvironment(t, s, tenant) - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -182,7 +182,7 @@ func TestRuntimeAllocationExpiryAndRevocation(t *testing.T) { if _, err := w.ReleaseRuntimeAllocation(t.Context(), owner); err != nil { t.Fatal(err) } - got, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, owner.ProviderKey, device.HashCredential(uuid.NewString())) + got, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, owner.ProviderKey, runtimedevice.HashCredential(uuid.NewString())) if err != nil || !got.Replayed || got.State != "released" || got.KeptAt.After(time.Now()) { t.Fatalf("cleanup permitted replacement: %+v %v", got, err) } diff --git a/services/core/internal/store/runtime_cancellation.go b/services/core/internal/store/runtime_cancellation.go index 48ac6527e..6f14db569 100644 --- a/services/core/internal/store/runtime_cancellation.go +++ b/services/core/internal/store/runtime_cancellation.go @@ -4,8 +4,8 @@ import ( "context" "errors" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/db/sqlc" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgtype" @@ -16,20 +16,20 @@ import ( // cannot authorize bootstrap, reconnect, dispatch, workspace access or renewal. // A marker records that archive caused the first revocation; timestamps alone // cannot distinguish an earlier ordinary cancel/revoke followed by archive. -func (s *Store) ArchivedCancellationReceipt(ctx context.Context, deviceID, credentialHash string, runIDs []string) (device.ArchivedCancellationReceipt, error) { +func (s *Store) ArchivedCancellationReceipt(ctx context.Context, deviceID, credentialHash string, runIDs []string) (runtimedevice.ArchivedCancellationReceipt, error) { if len(runIDs) == 0 || credentialHash == "" { - return device.ArchivedCancellationReceipt{}, nil + return runtimedevice.ArchivedCancellationReceipt{}, nil } id, err := parseID(deviceID) if err != nil { - return device.ArchivedCancellationReceipt{}, err + return runtimedevice.ArchivedCancellationReceipt{}, err } - row, err := s.queries.GetArchivedCancellationReceipt(ctx, sqlc.GetArchivedCancellationReceiptParams{DeviceID: id, CredentialHash: pgtype.Text{String: credentialHash, Valid: true}, RunIds: runIDs, LimitSeconds: int32(device.ArchivedCancellationReceiptLimit.Seconds())}) + row, err := s.queries.GetArchivedCancellationReceipt(ctx, sqlc.GetArchivedCancellationReceiptParams{DeviceID: id, CredentialHash: pgtype.Text{String: credentialHash, Valid: true}, RunIds: runIDs, LimitSeconds: int32(runtimedevice.ArchivedCancellationReceiptLimit.Seconds())}) if errors.Is(err, pgx.ErrNoRows) { - return device.ArchivedCancellationReceipt{}, nil + return runtimedevice.ArchivedCancellationReceipt{}, nil } if err != nil { - return device.ArchivedCancellationReceipt{}, err + return runtimedevice.ArchivedCancellationReceipt{}, err } - return device.ArchivedCancellationReceipt{RunID: uuid.UUID(row.ID.Bytes).String(), Deadline: row.CancelRequestedAt.Time.Add(device.ArchivedCancellationReceiptLimit)}, nil + return runtimedevice.ArchivedCancellationReceipt{RunID: uuid.UUID(row.ID.Bytes).String(), Deadline: row.CancelRequestedAt.Time.Add(runtimedevice.ArchivedCancellationReceiptLimit)}, nil } diff --git a/services/core/internal/store/runtime_compute_lifecycle_test.go b/services/core/internal/store/runtime_compute_lifecycle_test.go index e7934adbc..0626d5f1e 100644 --- a/services/core/internal/store/runtime_compute_lifecycle_test.go +++ b/services/core/internal/store/runtime_compute_lifecycle_test.go @@ -13,10 +13,10 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -33,7 +33,7 @@ type fakeCheckpointProvider struct { snapshots map[string]sandbox.SnapshotIdentity bootstraps map[string]sandbox.Bootstrap peers map[string]*websocket.Conn - registry *gateway.Registry + registry *runtimegateway.Registry endpoint string captures, restores, captureObservations, restoreObservations int computeKills, snapshotDeletes, wakeCommands int @@ -270,9 +270,9 @@ type computeLifecycleFixture struct { func newComputeLifecycleFixture(t *testing.T, maxActive, maxRetained int) *computeLifecycleFixture { t.Helper() s, pool := store.NewManagedTestStore(t) - registry := gateway.NewRegistry() + registry := runtimegateway.NewRegistry() p := &fakeCheckpointProvider{lifecycleProvider: lifecycleProvider{resources: map[string]sandbox.Info{}}, computes: map[string]sandbox.ComputeState{}, snapshots: map[string]sandbox.SnapshotIdentity{}, bootstraps: map[string]sandbox.Bootstrap{}, peers: map[string]*websocket.Conn{}, registry: registry} - handler := gateway.NewHandler(gateway.HandlerConfig{Authenticator: gateway.NewAuthenticator(s), Registry: registry}) + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Authenticator: runtimegateway.NewAuthenticator(s), Registry: registry}) server := httptest.NewServer(http.HandlerFunc(handler.WS)) p.endpoint = "ws" + strings.TrimPrefix(server.URL, "http") t.Cleanup(func() { diff --git a/services/core/internal/store/runtime_deployment_test.go b/services/core/internal/store/runtime_deployment_test.go index 75c6ccc6d..152bf4bb5 100644 --- a/services/core/internal/store/runtime_deployment_test.go +++ b/services/core/internal/store/runtime_deployment_test.go @@ -10,7 +10,7 @@ import ( "github.com/google/uuid" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" ) func deploymentSelection() RuntimeDeployment { @@ -117,7 +117,7 @@ func TestRuntimeDeploymentUnknownAllocationsBlockAdoptionAndSwitch(t *testing.T) old := deploymentSelection() tenant := uuid.NewString() session, environment := localEnvironment(t, s, tenant) - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -144,7 +144,7 @@ func TestRuntimeDeploymentUnknownAllocationsBlockAdoptionAndSwitch(t *testing.T) } deploymentConfigure(t, w, &old) _, environment = localEnvironment(t, s, tenant) - owner, err = w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())) + owner, err = w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -158,7 +158,7 @@ func TestRuntimeDeploymentUnknownAllocationsBlockAdoptionAndSwitch(t *testing.T) if err := w.ConfigureRuntimeDeployment(t.Context(), nil); err == nil { t.Fatal("removing adapter orphaned unknown creation") } - replay, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())) + replay, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil || !replay.Replayed || replay.ID != owner.ID { t.Fatal("maintenance blocked receipt replay", replay, err) } @@ -192,7 +192,7 @@ func TestRuntimeDeploymentMaintenancePreservesCreationRetriesAndOtherPlacements( if err := pool.QueryRow(t.Context(), "SELECT count(*) FROM sessions WHERE tenant_id=$1", tenant).Scan(&count); err != nil || count != 1 { t.Fatal("rejection left partial Session", count, err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())); !errors.Is(err, ErrEnvironmentUnavailable) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())); !errors.Is(err, ErrEnvironmentUnavailable) { t.Fatal("maintenance reserved new allocation", err) } for _, kind := range []string{"none", "self_hosted"} { @@ -204,10 +204,10 @@ func TestRuntimeDeploymentMaintenancePreservesCreationRetriesAndOtherPlacements( } old.AdmissionPaused = false deploymentConfigure(t, w, &old) - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())); !errors.Is(err, ErrEnvironmentUnavailable) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())); !errors.Is(err, ErrEnvironmentUnavailable) { t.Fatal("wrong installation reserved resource", err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())); err != nil { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, existing.Environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())); err != nil { t.Fatal("resume did not reopen allocation", err) } } @@ -259,7 +259,7 @@ func TestRuntimeDeploymentRetainedResourcesBlockSwitchWithoutMutation(t *testing deploymentConfigure(t, w, &old) tenant := uuid.NewString() _, environment := localEnvironment(t, s, tenant) - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, old.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -318,7 +318,7 @@ func TestRuntimeDeploymentAllocationBeforeMaintenanceRetainsOwnership(t *testing } allocated := make(chan error, 1) go func() { - _, err := w.ReserveRuntimeAllocation(ctx, tenant, environment.ID, config.InstallationID, device.HashCredential(uuid.NewString())) + _, err := w.ReserveRuntimeAllocation(ctx, tenant, environment.ID, config.InstallationID, runtimedevice.HashCredential(uuid.NewString())) allocated <- err }() runtimeSuspensionWaitBlocked(t, ctx, pool, blocker, allocated) diff --git a/services/core/internal/store/runtime_deployment_worker_test.go b/services/core/internal/store/runtime_deployment_worker_test.go index 5a6b9ad7f..3df49f0ae 100644 --- a/services/core/internal/store/runtime_deployment_worker_test.go +++ b/services/core/internal/store/runtime_deployment_worker_test.go @@ -4,8 +4,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -25,7 +25,7 @@ func TestManagedDeploymentStartupRejectsSwitchBeforeBackendAccess(t *testing.T) replacement := &lifecycleProvider{resources: map[string]sandbox.Info{}} config := &execution.RuntimeProvider{CoreURL: "http://core.invalid/api/v1", InstallationID: uuid.NewString(), BackendFingerprint: strings.Repeat("b", 64), Provider: replacement, AdmissionPaused: true} start := func(config *execution.RuntimeProvider) error { - _, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: config}) + _, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: config}) return err } if err := start(config); err == nil || !strings.Contains(err.Error(), "maintenance") { diff --git a/services/core/internal/store/runtime_enrollment_test.go b/services/core/internal/store/runtime_enrollment_test.go index d19ec673f..630178c33 100644 --- a/services/core/internal/store/runtime_enrollment_test.go +++ b/services/core/internal/store/runtime_enrollment_test.go @@ -5,9 +5,9 @@ import ( "sync" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/identity" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/google/uuid" ) @@ -55,7 +55,7 @@ func TestRuntimeEnrollmentAuthorityAndRotation(t *testing.T) { if devices, err := s.ListExecutionDevices(ctx, p.TenantID); err != nil || len(devices) != 0 { t.Fatalf("enrolled Runtime entered general selection: %v", err) } - auth := gateway.NewAuthenticator(s) + auth := runtimegateway.NewAuthenticator(s) if _, err := auth.AuthenticateBearer(ctx, bound.DeviceID, key.Token); err != nil { t.Fatal(err) } @@ -70,7 +70,7 @@ func TestRuntimeEnrollmentAuthorityAndRotation(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := auth.AuthenticateBearer(ctx, bound.DeviceID, key.Token); !errors.Is(err, gateway.ErrAuthBadCredential) { + if _, err := auth.AuthenticateBearer(ctx, bound.DeviceID, key.Token); !errors.Is(err, runtimegateway.ErrAuthBadCredential) { t.Fatalf("old key after rotation: %v", err) } if _, err := auth.AuthenticateBearer(ctx, bound.DeviceID, rotated.Token); err != nil { @@ -80,7 +80,7 @@ func TestRuntimeEnrollmentAuthorityAndRotation(t *testing.T) { token string denied bool }{{key.Token, true}, {rotated.Token, false}} { - status, err := s.TouchAgentDaemonHeartbeat(ctx, device.Heartbeat{RuntimeID: bound.DeviceID, CredentialHash: executorDigest(check.token)}) + status, err := s.TouchAgentDaemonHeartbeat(ctx, runtimedevice.Heartbeat{RuntimeID: bound.DeviceID, CredentialHash: executorDigest(check.token)}) if err != nil || status.Deleted != check.denied { t.Fatalf("rotation heartbeat: %+v %v", status, err) } @@ -145,7 +145,7 @@ func TestRuntimeEnrollmentConcurrentAndDeletion(t *testing.T) { if _, ok, err := s.GetDeviceCredential(t.Context(), bound.DeviceID); err != nil || ok { t.Fatalf("deleted Session authenticates: %v", err) } - status, err := s.TouchAgentDaemonHeartbeat(t.Context(), device.Heartbeat{RuntimeID: bound.DeviceID, CredentialHash: executorDigest(key.Token)}) + status, err := s.TouchAgentDaemonHeartbeat(t.Context(), runtimedevice.Heartbeat{RuntimeID: bound.DeviceID, CredentialHash: executorDigest(key.Token)}) if err != nil || !status.Deleted { t.Fatalf("deleted heartbeat: %+v %v", status, err) } diff --git a/services/core/internal/store/runtime_environment_terminal_test.go b/services/core/internal/store/runtime_environment_terminal_test.go index 8f3c31133..8a1b6baaf 100644 --- a/services/core/internal/store/runtime_environment_terminal_test.go +++ b/services/core/internal/store/runtime_environment_terminal_test.go @@ -6,7 +6,7 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) @@ -24,7 +24,7 @@ func TestManagedEnvironmentTerminationSettlesInputAndPreservesIdentity(t *testin } reservation := initialEnvironmentReservation(t, s, pool, tenant, session.ID) writer := executionLease(t, s).Store() - owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -119,7 +119,7 @@ func TestManagedEnvironmentFailureRollsBackWithSessionEvent(t *testing.T) { t.Fatal(err) } writer := executionLease(t, s).Store() - owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_idle_clock_test.go b/services/core/internal/store/runtime_idle_clock_test.go index 0675f3d2a..71890388d 100644 --- a/services/core/internal/store/runtime_idle_clock_test.go +++ b/services/core/internal/store/runtime_idle_clock_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/db/sqlc" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) @@ -26,7 +26,7 @@ func managedIdleClockFixture(t *testing.T) (*Store, *Store, RuntimeAllocation) { if err != nil { t.Fatal(err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential("runtime")) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_initialization_peer_test.go b/services/core/internal/store/runtime_initialization_peer_test.go index 7cd461555..32b119f41 100644 --- a/services/core/internal/store/runtime_initialization_peer_test.go +++ b/services/core/internal/store/runtime_initialization_peer_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/gorilla/websocket" ) @@ -22,7 +22,7 @@ import ( type initializationPeer struct { t *testing.T endpoint string - registry *gateway.Registry + registry *runtimegateway.Registry apply func(proto.RuntimePreparePayload, []byte) proto.RuntimePrepareResultPayload writes atomic.Int32 commandCalls atomic.Int32 @@ -31,7 +31,7 @@ type initializationPeer struct { bootstrap sandbox.Bootstrap } -func (p *initializationPeer) setRuntimeGateway(t *testing.T, endpoint string, registry *gateway.Registry) { +func (p *initializationPeer) setRuntimeGateway(t *testing.T, endpoint string, registry *runtimegateway.Registry) { p.t, p.endpoint, p.registry = t, endpoint, registry } func (p *initializationPeer) connect(b sandbox.Bootstrap) error { diff --git a/services/core/internal/store/runtime_lifecycle_nodes_test.go b/services/core/internal/store/runtime_lifecycle_nodes_test.go index 3e736931a..eee1bde1a 100644 --- a/services/core/internal/store/runtime_lifecycle_nodes_test.go +++ b/services/core/internal/store/runtime_lifecycle_nodes_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -36,7 +36,7 @@ func lifecycleTestSession(t *testing.T, s *Store, node string) (string, Session) func lifecycleTestAllocation(t *testing.T, s, w *Store, d RuntimeDeployment, node string) RuntimeAllocation { t.Helper() tenant, session := lifecycleTestSession(t, s, node) - allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential(uuid.NewString())) + allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -135,7 +135,7 @@ func TestRuntimeLifecycleNodeInventoryAndRouting(t *testing.T) { if _, err := w.ResolveRuntimeLifecycleNode(t.Context(), uuid.NewString(), environment); !errors.Is(err, ErrNotFound) { t.Fatal("tenant boundary", err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment, d.InstallationID, device.HashCredential("runtime")) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_lifecycle_test.go b/services/core/internal/store/runtime_lifecycle_test.go index 9f489fa18..d976cb022 100644 --- a/services/core/internal/store/runtime_lifecycle_test.go +++ b/services/core/internal/store/runtime_lifecycle_test.go @@ -12,9 +12,9 @@ import ( "github.com/google/uuid" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" ) @@ -33,7 +33,7 @@ func (p *lifecycleProvider) Create(_ context.Context, b sandbox.Bootstrap) (sand p.mu.Lock() defer p.mu.Unlock() p.creates++ - p.credentialHash = device.HashCredential(b.Credential) + p.credentialHash = runtimedevice.HashCredential(b.Credential) p.credential = b.Credential i := sandbox.Info{Reference: b.Reference, ProviderID: b.AllocationID, State: "running", BootstrapComplete: true} if !p.absent { @@ -78,11 +78,11 @@ func managedWorker(t *testing.T, s *store.Store, key string, p sandbox.SandboxPr func managedWorkerMode(t *testing.T, s *store.Store, key string, p sandbox.SandboxProvider, maintenance bool, run ...bool) (*execution.Worker, func()) { t.Helper() - registry := gateway.NewRegistry() + registry := runtimegateway.NewRegistry() if peer, ok := p.(interface { - setRuntimeGateway(*testing.T, string, *gateway.Registry) + setRuntimeGateway(*testing.T, string, *runtimegateway.Registry) }); ok { - handler := gateway.NewHandler(gateway.HandlerConfig{Authenticator: gateway.NewAuthenticator(s), Registry: registry}) + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Authenticator: runtimegateway.NewAuthenticator(s), Registry: registry}) server := httptest.NewServer(http.HandlerFunc(handler.WS)) t.Cleanup(server.Close) peer.setRuntimeGateway(t, "ws"+strings.TrimPrefix(server.URL, "http"), registry) diff --git a/services/core/internal/store/runtime_node_generations_test.go b/services/core/internal/store/runtime_node_generations_test.go index e3f532942..a13cbf748 100644 --- a/services/core/internal/store/runtime_node_generations_test.go +++ b/services/core/internal/store/runtime_node_generations_test.go @@ -8,7 +8,7 @@ import ( "os" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/google/uuid" ) @@ -112,7 +112,7 @@ func TestNodeGenerationsCapacityFallbackAndImmutablePending(t *testing.T) { t.Fatal("late readiness moved pin or erased serving readiness", n) } } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, pending.Environment.ID, first.InstallationID, device.HashCredential("runtime")) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, pending.Environment.ID, first.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_node_lifecycle_fixture_test.go b/services/core/internal/store/runtime_node_lifecycle_fixture_test.go index 85fab0ed2..94352bc34 100644 --- a/services/core/internal/store/runtime_node_lifecycle_fixture_test.go +++ b/services/core/internal/store/runtime_node_lifecycle_fixture_test.go @@ -13,11 +13,11 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -94,7 +94,7 @@ func newNodeIsolationFixture(t *testing.T, mode string) *nodeIsolationFixture { t.Fatal(err) } s := store.NewWithCredentialCipher(pool, cipher) - registry := gateway.NewRegistry() + registry := runtimegateway.NewRegistry() cp := &fakeCheckpointProvider{lifecycleProvider: lifecycleProvider{resources: map[string]sandbox.Info{}}, computes: map[string]sandbox.ComputeState{}, snapshots: map[string]sandbox.SnapshotIdentity{}, bootstraps: map[string]sandbox.Bootstrap{}, peers: map[string]*websocket.Conn{}, registry: registry} p := &nodeIsolationProvider{fakeCheckpointProvider: cp, blocked: map[string]bool{}, mode: mode, entered: make(chan struct{})} preparationContext, cancelPreparation := context.WithCancel(t.Context()) @@ -110,7 +110,7 @@ func newNodeIsolationFixture(t *testing.T, mode string) *nodeIsolationFixture { p.writes.Add(1) return completedInitialization(request, data) }} - handler := gateway.NewHandler(gateway.HandlerConfig{Authenticator: gateway.NewAuthenticator(s), Registry: registry}) + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Authenticator: runtimegateway.NewAuthenticator(s), Registry: registry}) server := httptest.NewServer(http.HandlerFunc(handler.WS)) cp.endpoint = "ws" + strings.TrimPrefix(server.URL, "http") t.Cleanup(func() { @@ -125,7 +125,7 @@ func newNodeIsolationFixture(t *testing.T, mode string) *nodeIsolationFixture { // Keep restored compute awake throughout the isolation assertions. // The suspension setup explicitly dates its activity two minutes in the past. policy := &execution.RuntimeSuspensionPolicy{IdleTimeout: time.Minute, Retention: time.Hour, MaxActive: 100, MaxRetained: 100} - f.worker, err = execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: registry, ManagedRuntimes: &execution.RuntimeProvider{CoreURL: "http://core.invalid/api/v1", InstallationID: f.key, BackendFingerprint: strings.Repeat("a", 64), Provider: p, ProviderKind: "microsandbox", LocalNodeID: f.nodeA, LocalCredentialSHA256: device.HashCredential("local-credential"), LocalMaxActive: 100, LocalMaxRetained: 100, Suspension: policy}}) + f.worker, err = execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: registry, ManagedRuntimes: &execution.RuntimeProvider{CoreURL: "http://core.invalid/api/v1", InstallationID: f.key, BackendFingerprint: strings.Repeat("a", 64), Provider: p, ProviderKind: "microsandbox", LocalNodeID: f.nodeA, LocalCredentialSHA256: runtimedevice.HashCredential("local-credential"), LocalMaxActive: 100, LocalMaxRetained: 100, Suspension: policy}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_nodes_test.go b/services/core/internal/store/runtime_nodes_test.go index d11808250..093651f2f 100644 --- a/services/core/internal/store/runtime_nodes_test.go +++ b/services/core/internal/store/runtime_nodes_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) @@ -21,7 +21,7 @@ func managerFixture(t *testing.T, active, retained int) (*Store, *Store, Runtime d := deploymentSelection() d.ProviderKind = "docker" d.LocalNodeID = uuid.NewString() - d.LocalCredentialSHA256 = device.HashCredential("local-node-credential") + d.LocalCredentialSHA256 = runtimedevice.HashCredential("local-node-credential") d.LocalMaxActive = active d.LocalMaxRetained = retained deploymentConfigure(t, w, &d) @@ -238,7 +238,7 @@ func TestRuntimeNodesRetention(t *testing.T) { if err != nil { t.Fatal(err) } - retained, err := w.ReserveRuntimeAllocation(t.Context(), tenant, first.Environment.ID, next.InstallationID, device.HashCredential("runtime")) + retained, err := w.ReserveRuntimeAllocation(t.Context(), tenant, first.Environment.ID, next.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } @@ -294,7 +294,7 @@ func TestRuntimeNodesRestoreAndCreationShareCapacity(t *testing.T) { if err != nil { t.Fatal(err) } - allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential("runtime")) + allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } @@ -352,7 +352,7 @@ func TestRuntimeNodesLongOfflineRetainsExactAllocation(t *testing.T) { if err != nil { t.Fatal(err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential("runtime")) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_observation_test.go b/services/core/internal/store/runtime_observation_test.go index b72351c2c..4052fc8f4 100644 --- a/services/core/internal/store/runtime_observation_test.go +++ b/services/core/internal/store/runtime_observation_test.go @@ -4,7 +4,7 @@ import ( "errors" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -15,7 +15,7 @@ func TestRuntimeNodeObservationRetainsResourcesAndFencesStaleResults(t *testing. if err != nil { t.Fatal(err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential("runtime")) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_pending_test.go b/services/core/internal/store/runtime_pending_test.go index 82259eb92..26bc8fed1 100644 --- a/services/core/internal/store/runtime_pending_test.go +++ b/services/core/internal/store/runtime_pending_test.go @@ -5,8 +5,8 @@ import ( "encoding/json" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -26,7 +26,7 @@ func TestManagedRuntimeAutomaticBootstrapRecoversCommittedSessions(t *testing.T) key := uuid.NewString() p := &lifecycleProvider{resources: map[string]sandbox.Info{}} start := func() *execution.Worker { - w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: &execution.RuntimeProvider{CoreURL: "http://core.invalid/api/v1", InstallationID: key, BackendFingerprint: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Provider: p}}) + w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: &execution.RuntimeProvider{CoreURL: "http://core.invalid/api/v1", InstallationID: key, BackendFingerprint: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", Provider: p}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/runtime_suspension_test.go b/services/core/internal/store/runtime_suspension_test.go index db73eb995..53fc609c1 100644 --- a/services/core/internal/store/runtime_suspension_test.go +++ b/services/core/internal/store/runtime_suspension_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" ) @@ -19,7 +19,7 @@ func runtimeSuspensionFixture(t *testing.T) (*Store, *Store, *pgxpool.Pool, Runt w := executionLease(t, s).Store() tenant := uuid.NewString() _, environment := localEnvironment(t, s, tenant) - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -274,7 +274,7 @@ func TestRuntimeSuspensionCountsUncertainCapacityUntilReleased(t *testing.T) { for _, item := range cases { tenant := uuid.NewString() _, env := localEnvironment(t, s, tenant) - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, env.ID, provider, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, env.ID, provider, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -458,7 +458,7 @@ func TestRuntimeComputePhaseChangedAtInNodeAllocations(t *testing.T) { if err != nil { t.Fatal(err) } - allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, device.HashCredential("runtime")) + allocation, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, d.InstallationID, runtimedevice.HashCredential("runtime")) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/sandbox_deployment_resources_test.go b/services/core/internal/store/sandbox_deployment_resources_test.go index deefa1f5f..b4c9800b1 100644 --- a/services/core/internal/store/sandbox_deployment_resources_test.go +++ b/services/core/internal/store/sandbox_deployment_resources_test.go @@ -4,8 +4,8 @@ import ( "bytes" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -30,7 +30,7 @@ func TestSandboxDeploymentMutationViewsIncludeActualResources(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, device.HashCredential(uuid.NewString())); err != nil { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, runtimedevice.HashCredential(uuid.NewString())); err != nil { t.Fatal(err) } if _, err := s.CreateSession(t.Context(), tenant, managerSessionInput(uuid.NewString())); err != nil { diff --git a/services/core/internal/store/sandbox_deployment_switch_test.go b/services/core/internal/store/sandbox_deployment_switch_test.go index c8b73e31c..b64a643d1 100644 --- a/services/core/internal/store/sandbox_deployment_switch_test.go +++ b/services/core/internal/store/sandbox_deployment_switch_test.go @@ -10,8 +10,8 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -125,7 +125,7 @@ func TestSandboxDirectDeploymentOwnershipAndCleanSwitch(t *testing.T) { if err != nil || len(nodes) != 1 || nodes[0] != "" { t.Fatal("cloud lifecycle requires node", nodes, err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment, id, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment, id, runtimedevice.HashCredential(uuid.NewString())) if err != nil || owner.NodeID != "" { t.Fatal(owner, err) } @@ -305,7 +305,7 @@ func TestSandboxSwitchPreservesReleasedAllocationAndItemHistory(t *testing.T) { if err != nil { t.Fatal(err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, installation, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/sandbox_deployment_switch_worker_test.go b/services/core/internal/store/sandbox_deployment_switch_worker_test.go index 313d4b4d4..b60453c6a 100644 --- a/services/core/internal/store/sandbox_deployment_switch_worker_test.go +++ b/services/core/internal/store/sandbox_deployment_switch_worker_test.go @@ -12,9 +12,9 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -41,7 +41,7 @@ func TestSandboxWorkerSwitchesAndRecoversFailedActivation(t *testing.T) { } return execution.PreparedRuntimeDeployment{Config: &execution.RuntimeProvider{InstallationID: setup.InstallationID, ProviderKind: setup.Provider, Mode: setup.Mode, AdmissionPaused: setup.AdmissionPaused, CoreURL: "https://core.example/api/v1", BackendFingerprint: setup.BackendFingerprint, Provider: p}}, nil }) - w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: configuration}) + w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: configuration}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/sandbox_deployment_worker_test.go b/services/core/internal/store/sandbox_deployment_worker_test.go index 4da5f54d0..37ac7d790 100644 --- a/services/core/internal/store/sandbox_deployment_worker_test.go +++ b/services/core/internal/store/sandbox_deployment_worker_test.go @@ -8,8 +8,8 @@ import ( "sync" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" @@ -31,7 +31,7 @@ func TestSandboxDeploymentWorkerActivatesWithoutRestart(t *testing.T) { }) start := func() (*execution.Worker, func()) { t.Helper() - w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry(), ManagedRuntimes: configuration}) + w, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry(), ManagedRuntimes: configuration}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/sandbox_node_auth_order_http_test.go b/services/core/internal/store/sandbox_node_auth_order_http_test.go index 2fe002ef9..ea7855a65 100644 --- a/services/core/internal/store/sandbox_node_auth_order_http_test.go +++ b/services/core/internal/store/sandbox_node_auth_order_http_test.go @@ -7,8 +7,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -18,7 +18,7 @@ import ( // recognized credential learns that the deployment is unavailable. func TestSandboxNodeRoutesAuthenticateBeforeDeploymentState(t *testing.T) { s, pool := store.NewManagedTestStore(t) - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential(uuid.NewString())}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(uuid.NewString())}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/sandbox_specification_store_test.go b/services/core/internal/store/sandbox_specification_store_test.go index 8c0313f12..135412bcc 100644 --- a/services/core/internal/store/sandbox_specification_store_test.go +++ b/services/core/internal/store/sandbox_specification_store_test.go @@ -10,8 +10,8 @@ import ( "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sandbox/e2b" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -168,7 +168,7 @@ func TestSandboxSpecificationChangesPreserveEveryRetainedResource(t *testing.T) } var owner RuntimeAllocation if state != "pending" { - owner, err = w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, view.InstallationID, device.HashCredential(uuid.NewString())) + owner, err = w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, view.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -310,7 +310,7 @@ func TestSandboxSpecificationAllocationRaceWithMaintenance(t *testing.T) { for _, session := range sessions { go func() { <-start - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, view.InstallationID, device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, view.InstallationID, runtimedevice.HashCredential(uuid.NewString())) results <- result{session, owner, err} }() } @@ -328,7 +328,7 @@ func TestSandboxSpecificationAllocationRaceWithMaintenance(t *testing.T) { result := <-results if result.err == nil { allocated++ - retry, err := w.ReserveRuntimeAllocation(t.Context(), tenant, result.session.Environment.ID, view.InstallationID, device.HashCredential(uuid.NewString())) + retry, err := w.ReserveRuntimeAllocation(t.Context(), tenant, result.session.Environment.ID, view.InstallationID, runtimedevice.HashCredential(uuid.NewString())) if err != nil || retry.ID != result.owner.ID || !retry.Replayed { t.Fatal("maintenance changed an admitted allocation retry", err) } @@ -336,7 +336,7 @@ func TestSandboxSpecificationAllocationRaceWithMaintenance(t *testing.T) { if !errors.Is(result.err, ErrSandboxResetAdmission) { t.Fatal("allocation race failed outside admission", result.err) } - if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, result.session.Environment.ID, view.InstallationID, device.HashCredential(uuid.NewString())); !errors.Is(err, ErrSandboxResetAdmission) { + if _, err := w.ReserveRuntimeAllocation(t.Context(), tenant, result.session.Environment.ID, view.InstallationID, runtimedevice.HashCredential(uuid.NewString())); !errors.Is(err, ErrSandboxResetAdmission) { t.Fatal("fresh allocation passed committed maintenance", err) } } diff --git a/services/core/internal/store/saved_web_search_public_test.go b/services/core/internal/store/saved_web_search_public_test.go index 2bd0224fb..fec0e9d3a 100644 --- a/services/core/internal/store/saved_web_search_public_test.go +++ b/services/core/internal/store/saved_web_search_public_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -23,8 +23,8 @@ func TestSavedWebSearchPostgres(t *testing.T) { s, pool := store.NewManagedTestStore(t) owner, foreign, ownerTenant := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "search-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "search-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "search-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "search-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/self_hosted_cancel_public_test.go b/services/core/internal/store/self_hosted_cancel_public_test.go index 8719b8a2c..47beb1a9a 100644 --- a/services/core/internal/store/self_hosted_cancel_public_test.go +++ b/services/core/internal/store/self_hosted_cancel_public_test.go @@ -11,8 +11,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -26,8 +26,8 @@ func TestSelfHostedCancellationOfficialClient(t *testing.T) { tenant, foreignTenant := uuid.NewString(), uuid.NewString() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "cancel-caller", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "cancel-caller", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "cancel-caller", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "cancel-caller", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/self_hosted_initial_public_test.go b/services/core/internal/store/self_hosted_initial_public_test.go index 7f035146e..c5bb6a3af 100644 --- a/services/core/internal/store/self_hosted_initial_public_test.go +++ b/services/core/internal/store/self_hosted_initial_public_test.go @@ -15,10 +15,10 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgxpool" @@ -33,9 +33,9 @@ func TestSelfHostedInitialCreationOfficialClient(t *testing.T) { tenant, foreignTenant := uuid.NewString(), uuid.NewString() token, peer, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "initial-creator", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "user", SubjectID: "different-creator", TokenSHA256: device.HashCredential(peer), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "initial-creator", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "initial-creator", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "user", SubjectID: "different-creator", TokenSHA256: runtimedevice.HashCredential(peer), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "initial-creator", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) @@ -202,7 +202,7 @@ func TestSelfHostedInitialCreationOfficialClient(t *testing.T) { func publicInitialWorker(t *testing.T, s *store.Store) (*execution.Worker, func(bool)) { t.Helper() - dispatcher := &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry()} + dispatcher := &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry()} worker, err := execution.StartWorker(t.Context(), dispatcher) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/session_agent_filter_public_test.go b/services/core/internal/store/session_agent_filter_public_test.go index 7e91b48d0..1ef909dcc 100644 --- a/services/core/internal/store/session_agent_filter_public_test.go +++ b/services/core/internal/store/session_agent_filter_public_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -22,8 +22,8 @@ func TestSessionAgentFilterOfficialClient(t *testing.T) { s, pool := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/session_artifacts_public_test.go b/services/core/internal/store/session_artifacts_public_test.go index e336d7a46..4f7afe53f 100644 --- a/services/core/internal/store/session_artifacts_public_test.go +++ b/services/core/internal/store/session_artifacts_public_test.go @@ -16,8 +16,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -74,8 +74,8 @@ func artifactHTTPServer(t *testing.T, s *store.Store) (server *httptest.Server, owner, foreign = uuid.NewString(), uuid.NewString() ownerTenant, foreignTenant = uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "artifact-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "artifact-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "artifact-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "artifact-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/session_deletion_lifecycle_public_test.go b/services/core/internal/store/session_deletion_lifecycle_public_test.go index b0db485f6..ee49e9214 100644 --- a/services/core/internal/store/session_deletion_lifecycle_public_test.go +++ b/services/core/internal/store/session_deletion_lifecycle_public_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -27,8 +27,8 @@ func TestSessionDeletionLifecyclePostgres(t *testing.T) { ctx := t.Context() tenant, owner, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "deletion-owner", TokenSHA256: device.HashCredential(owner), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "deletion-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "deletion-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "deletion-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) @@ -229,7 +229,7 @@ func TestSessionDeletionLifecyclePostgres(t *testing.T) { t.Fatal("repeated deletion must append exactly two operation records", err) } for _, operation := range afterAudit.Data[:2] { - if operation.Action != "delete" || operation.APIKey.ID != uuid.NewSHA1(uuid.NameSpaceOID, []byte(device.HashCredential(owner))).String() { + if operation.Action != "delete" || operation.APIKey.ID != uuid.NewSHA1(uuid.NameSpaceOID, []byte(runtimedevice.HashCredential(owner))).String() { t.Fatal("repeated deletion recorded the wrong operation or key") } } diff --git a/services/core/internal/store/session_deletion_public_test.go b/services/core/internal/store/session_deletion_public_test.go index e16cdde0d..939ade92e 100644 --- a/services/core/internal/store/session_deletion_public_test.go +++ b/services/core/internal/store/session_deletion_public_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -22,8 +22,8 @@ func TestSessionDeletionOfficialClient(t *testing.T) { s, pool := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/session_diagnostics_test.go b/services/core/internal/store/session_diagnostics_test.go index 95824720a..4c80d667f 100644 --- a/services/core/internal/store/session_diagnostics_test.go +++ b/services/core/internal/store/session_diagnostics_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/db/sqlc" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) @@ -204,7 +204,7 @@ func TestDiagnosticProvisioningDetailAtomicAndPrivate(t *testing.T) { t.Fatal(err) } writer := executionLease(t, s).Store() - owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := writer.ReserveRuntimeAllocation(t.Context(), tenant, session.Environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/session_execution_configuration_test.go b/services/core/internal/store/session_execution_configuration_test.go index 6ab3d8c43..7310abe46 100644 --- a/services/core/internal/store/session_execution_configuration_test.go +++ b/services/core/internal/store/session_execution_configuration_test.go @@ -10,8 +10,8 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -258,7 +258,7 @@ func TestSessionExecutionConfigurationSurvivesSuspendResume(t *testing.T) { if err != nil { t.Fatal(err) } - owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), device.HashCredential(uuid.NewString())) + owner, err := w.ReserveRuntimeAllocation(t.Context(), tenant, environment.ID, uuid.NewString(), runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/session_initial_public_test.go b/services/core/internal/store/session_initial_public_test.go index 28ac362ea..a431ba8e3 100644 --- a/services/core/internal/store/session_initial_public_test.go +++ b/services/core/internal/store/session_initial_public_test.go @@ -7,9 +7,9 @@ import ( "os/exec" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -21,7 +21,7 @@ func TestInitialSessionInputOfficialClient(t *testing.T) { } s, _ := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/session_model_execution_http_test.go b/services/core/internal/store/session_model_execution_http_test.go index f52533b49..1de03a926 100644 --- a/services/core/internal/store/session_model_execution_http_test.go +++ b/services/core/internal/store/session_model_execution_http_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -19,7 +19,7 @@ func TestModelExecutionHTTPWriteOnlyAndStrictAdmission(t *testing.T) { cipher, _ := credentialcrypto.New(bytes.Repeat([]byte{6}, 32)) st := store.NewWithCredentialCipher(pool, cipher) tenant, token := uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "catalog-test", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "catalog-test", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/session_reference_retry_public_test.go b/services/core/internal/store/session_reference_retry_public_test.go index f72d91cde..76a05efe9 100644 --- a/services/core/internal/store/session_reference_retry_public_test.go +++ b/services/core/internal/store/session_reference_retry_public_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -24,7 +24,7 @@ func TestSavedReferenceRetryOfficialClient(t *testing.T) { } s, pool := store.NewTestStore(t) tenant, token, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/skill_selectors_public_test.go b/services/core/internal/store/skill_selectors_public_test.go index 092a9ff7d..1d71d21c0 100644 --- a/services/core/internal/store/skill_selectors_public_test.go +++ b/services/core/internal/store/skill_selectors_public_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -30,8 +30,8 @@ func TestSkillSelectorsOfficialClientPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/skill_version_deletion_public_test.go b/services/core/internal/store/skill_version_deletion_public_test.go index 926d59122..45b6250f9 100644 --- a/services/core/internal/store/skill_version_deletion_public_test.go +++ b/services/core/internal/store/skill_version_deletion_public_test.go @@ -9,9 +9,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -29,8 +29,8 @@ func TestSkillVersionDeletionHTTPPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) owner, foreign, ownerTenant := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "skill-owner", TokenSHA256: device.HashCredential(owner), TenantID: ownerTenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "skill-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "skill-owner", TokenSHA256: runtimedevice.HashCredential(owner), TenantID: ownerTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "skill-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/skills_public_test.go b/services/core/internal/store/skills_public_test.go index c82a6c519..17de4ad95 100644 --- a/services/core/internal/store/skills_public_test.go +++ b/services/core/internal/store/skills_public_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -30,8 +30,8 @@ func TestSkillsOfficialClientPostgres(t *testing.T) { s := store.NewWithCredentialCipher(pool, cipher) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/source_files_errors_public_test.go b/services/core/internal/store/source_files_errors_public_test.go index a5b836eee..b79ec755d 100644 --- a/services/core/internal/store/source_files_errors_public_test.go +++ b/services/core/internal/store/source_files_errors_public_test.go @@ -8,8 +8,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -22,8 +22,8 @@ func TestSourceFileErrorsOfficialClientPostgres(t *testing.T) { s, _ := store.NewTestStore(t) token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "files-owner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "files-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "files-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "files-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/structured_output_native_test.go b/services/core/internal/store/structured_output_native_test.go index 412cef7f6..1d986ec24 100644 --- a/services/core/internal/store/structured_output_native_test.go +++ b/services/core/internal/store/structured_output_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -58,8 +58,8 @@ func TestNativeStructuredOutputPublicExecution(t *testing.T) { }() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/subagent_identities_test.go b/services/core/internal/store/subagent_identities_test.go index ab07aeb88..245db7fdc 100644 --- a/services/core/internal/store/subagent_identities_test.go +++ b/services/core/internal/store/subagent_identities_test.go @@ -7,8 +7,8 @@ import ( "reflect" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -24,7 +24,7 @@ func TestSubagentIdentityIsAtomicScopedAndImmutable(t *testing.T) { w := lease.Store() ctx := t.Context() tenant, session := newSubagentSession(t, s) - host, err := s.CreateDevice(ctx, tenant, "identity test", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(ctx, tenant, "identity test", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/subagent_native_outputs_test.go b/services/core/internal/store/subagent_native_outputs_test.go index 9b64866d8..dbfc3b7a6 100644 --- a/services/core/internal/store/subagent_native_outputs_test.go +++ b/services/core/internal/store/subagent_native_outputs_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -15,7 +15,7 @@ func TestSubagentNativeFunctionResultDoesNotConsumeOutputIndex(t *testing.T) { s, pool := testStore(t) owner := executionLease(t, s).Store() tenant, session := newSubagentSession(t, s) - host, err := s.CreateDevice(t.Context(), tenant, "child outputs", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(t.Context(), tenant, "child outputs", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } @@ -89,7 +89,7 @@ func TestSubagentCancelledPartialMessageSurvivesHistoryReplay(t *testing.T) { s, _ := testStore(t) owner := executionLease(t, s).Store() tenant, session := newSubagentSession(t, s) - host, err := s.CreateDevice(t.Context(), tenant, "cancelled child", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(t.Context(), tenant, "cancelled child", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/subagent_resources_test.go b/services/core/internal/store/subagent_resources_test.go index 7f2eb9894..a651c577b 100644 --- a/services/core/internal/store/subagent_resources_test.go +++ b/services/core/internal/store/subagent_resources_test.go @@ -8,8 +8,8 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/google/uuid" ) @@ -31,7 +31,7 @@ func TestSubagentResourcesNativeOwnershipLifecycleAndRecovery(t *testing.T) { owner := executionLease(t, s).Store() ctx := t.Context() tenant, session := newSubagentSession(t, s) - host, err := s.CreateDevice(ctx, tenant, "child resources", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(ctx, tenant, "child resources", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/subagent_visibility_public_test.go b/services/core/internal/store/subagent_visibility_public_test.go index 684428e51..85a5cbcc8 100644 --- a/services/core/internal/store/subagent_visibility_public_test.go +++ b/services/core/internal/store/subagent_visibility_public_test.go @@ -8,9 +8,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -73,8 +73,8 @@ func TestSubagentVisibilityPublic(t *testing.T) { s, _ := store.NewTestStore(t) tenant, token, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "foreign", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test-org", ProjectID: tenant, SubjectKind: "service_account", SubjectID: "test-runner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) @@ -128,7 +128,7 @@ func TestSubagentVisibilityPublic(t *testing.T) { t.Fatal(page, err) } root := page.Turns[0].ID - host, err := s.CreateDevice(ctx, tenant, "subagent visibility", device.HashCredential(uuid.NewString())) + host, err := s.CreateDevice(ctx, tenant, "subagent visibility", runtimedevice.HashCredential(uuid.NewString())) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/template_composition_public_test.go b/services/core/internal/store/template_composition_public_test.go index 3ab0acda0..c9f5de1ed 100644 --- a/services/core/internal/store/template_composition_public_test.go +++ b/services/core/internal/store/template_composition_public_test.go @@ -13,9 +13,9 @@ import ( "time" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -34,8 +34,8 @@ func TestTemplateCompositionOfficialClientPostgres(t *testing.T) { reopenedStore := store.NewWithCredentialCipher(pool, cipher) tenant, foreignTenant, token, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "composition-owner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "composition-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "composition-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "composition-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/template_null_selection_public_test.go b/services/core/internal/store/template_null_selection_public_test.go index e651b127a..a78579baa 100644 --- a/services/core/internal/store/template_null_selection_public_test.go +++ b/services/core/internal/store/template_null_selection_public_test.go @@ -14,10 +14,10 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/internal/agentplugin" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -36,8 +36,8 @@ func TestTemplateNullSelectionOfficialClientPostgres(t *testing.T) { reopenedStore := store.NewWithCredentialCipher(pool, cipher) tenant, foreignTenant, token, foreign := uuid.NewString(), uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-owner", TokenSHA256: device.HashCredential(token), TenantID: tenant}, - {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-foreign", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}, + {OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "selection-foreign", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/tool_policy_native_test.go b/services/core/internal/store/tool_policy_native_test.go index 8d763354c..9b528c108 100644 --- a/services/core/internal/store/tool_policy_native_test.go +++ b/services/core/internal/store/tool_policy_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -64,8 +64,8 @@ func TestNativeToolPolicyPublicExecution(t *testing.T) { }() token, foreign, foreignTenant := uuid.NewString(), uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: foreignTenant}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: foreignTenant, SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: foreignTenant}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/tool_search_native_test.go b/services/core/internal/store/tool_search_native_test.go index bc71be7d8..4e98d44bf 100644 --- a/services/core/internal/store/tool_search_native_test.go +++ b/services/core/internal/store/tool_search_native_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -58,8 +58,8 @@ func TestNativeToolSearchPublicExecution(t *testing.T) { }() token, foreign := uuid.NewString(), uuid.NewString() auth, err := newTestAuthenticator([]testAPIKey{ - {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: device.HashCredential(token), TenantID: h.tenant}, - {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: device.HashCredential(foreign), TenantID: uuid.NewString()}, + {OrganizationID: "test", ProjectID: h.tenant, SubjectKind: "service_account", SubjectID: "owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: h.tenant}, + {OrganizationID: "test", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "other", TokenSHA256: runtimedevice.HashCredential(foreign), TenantID: uuid.NewString()}, }) if err != nil { t.Fatal(err) diff --git a/services/core/internal/store/unified_model_configuration_http_test.go b/services/core/internal/store/unified_model_configuration_http_test.go index 6edba0dbe..2213c7d12 100644 --- a/services/core/internal/store/unified_model_configuration_http_test.go +++ b/services/core/internal/store/unified_model_configuration_http_test.go @@ -8,8 +8,8 @@ import ( "testing" v1 "github.com/MiniMax-AI/OpenAgentCore/contracts/agents-api/v1" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -17,11 +17,11 @@ import ( func TestUnifiedModelConfigurationHTTP(t *testing.T) { st, _ := store.NewManagedTestStore(t) tenant, token, coreKey := uuid.NewString(), uuid.NewString(), uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "model-configuration", TokenSHA256: device.HashCredential(token), TenantID: tenant}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "model-configuration", TokenSHA256: runtimedevice.HashCredential(token), TenantID: tenant}}) if err != nil { t.Fatal(err) } - admin, err := api.NewDeploymentAuthenticator([]string{device.HashCredential(coreKey)}) + admin, err := api.NewDeploymentAuthenticator([]string{runtimedevice.HashCredential(coreKey)}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/unstorable_text_public_test.go b/services/core/internal/store/unstorable_text_public_test.go index 8b8783038..f01d923cf 100644 --- a/services/core/internal/store/unstorable_text_public_test.go +++ b/services/core/internal/store/unstorable_text_public_test.go @@ -10,9 +10,9 @@ import ( "strings" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/credentialcrypto" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -28,7 +28,7 @@ func TestUnstorableTextRejectsWithoutWritesPostgres(t *testing.T) { } s := store.NewWithCredentialCipher(pool, cipher) token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "nul-owner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "nul-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } diff --git a/services/core/internal/store/whitespace_input_public_test.go b/services/core/internal/store/whitespace_input_public_test.go index b2df5c6a5..c46e26561 100644 --- a/services/core/internal/store/whitespace_input_public_test.go +++ b/services/core/internal/store/whitespace_input_public_test.go @@ -8,10 +8,10 @@ import ( "reflect" "testing" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/device" - "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/gateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/api" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/execution" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store" "github.com/google/uuid" ) @@ -23,7 +23,7 @@ func TestWhitespaceInputStoredVerbatimPostgres(t *testing.T) { // An isolated database keeps the no-write digest independent of other tests. s, pool := store.NewManagedTestStore(t) token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "whitespace-owner", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "whitespace-owner", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } @@ -100,12 +100,12 @@ func TestWhitespaceInputStoredVerbatimPostgres(t *testing.T) { func TestWhitespaceOnlyTextHarnessAdmissionPostgres(t *testing.T) { s, pool := store.NewManagedTestStore(t) token := uuid.NewString() - auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "whitespace-harness", TokenSHA256: device.HashCredential(token), TenantID: uuid.NewString()}}) + auth, err := newTestAuthenticator([]testAPIKey{{OrganizationID: "test-org", ProjectID: uuid.NewString(), SubjectKind: "service_account", SubjectID: "whitespace-harness", TokenSHA256: runtimedevice.HashCredential(token), TenantID: uuid.NewString()}}) if err != nil { t.Fatal(err) } // Real Worker admission with dispatch paused keeps admitted Turns queued. - worker, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: gateway.NewRegistry()}) + worker, err := execution.StartWorker(t.Context(), &execution.Dispatcher{Store: s, Registry: runtimegateway.NewRegistry()}) if err != nil { t.Fatal(err) } From 16a3e2fe7b5bff236cf93c078931673c567df853 Mon Sep 17 00:00:00 2001 From: SaladDay <1203511142@qq.com> Date: Wed, 30 Sep 2026 10:54:35 +0000 Subject: [PATCH 2/2] =?UTF-8?q?Check=20the=20Core=E2=80=93Runtime=20wire?= =?UTF-8?q?=20contract=20against=20shared=20scenarios?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit internal/agentdaemon/proto/prototest/wire.go defines each exchange once: the ordered frames Core and the Runtime send, built from the proto types, plus the native settlement, connection loss, reconnection and silence between them, and the incompatible-version handshake. Each side replays the other side's frames from a scripted peer over a real WebSocket and asserts what it owns: - services/core/internal/runtimegateway/wire_test.go runs Core's gateway: the 426 rejection, delivery to preparation, Run and receipt waiters, no receipt before the Runtime's acknowledgement, no invented terminal events on disconnect and no inherited routes or replay after reconnect. - apps/daemon/internal/wireconformance runs the production transport and dispatcher with the controlled adapter: permanent stop on 426, the exact frames it sends, no input during preparation, cleanup on failure, no receipt before native settlement, and settled cleanup after connection loss. Runtime-generated values (Executor ID, handle, expiry) are placeholders that the Runtime side binds to the values its Runtime sends. --- Makefile | 2 +- .../internal/wireconformance/wire_test.go | 371 ++++++++++++++++++ docs/runtime-protocol.md | 6 +- .../proto/prototest/capabilities.go | 3 +- internal/agentdaemon/proto/prototest/wire.go | 261 ++++++++++++ .../agentdaemon/proto/prototest/wire_test.go | 35 ++ scripts/name-allowlist.json | 5 + .../core/internal/runtimegateway/wire_test.go | 361 +++++++++++++++++ 8 files changed, 1040 insertions(+), 4 deletions(-) create mode 100644 apps/daemon/internal/wireconformance/wire_test.go create mode 100644 internal/agentdaemon/proto/prototest/wire.go create mode 100644 internal/agentdaemon/proto/prototest/wire_test.go create mode 100644 services/core/internal/runtimegateway/wire_test.go diff --git a/Makefile b/Makefile index 95bfcf238..f0dea91dd 100644 --- a/Makefile +++ b/Makefile @@ -51,7 +51,7 @@ check-go: .PHONY: check-runtime-contract check-runtime-contract: - go test ./internal/agentdaemon/proto ./services/core/internal/runtimegateway ./apps/daemon/internal/transport ./apps/daemon/internal/dispatch -count=1 + go test ./internal/agentdaemon/proto/... ./services/core/internal/runtimegateway ./apps/daemon/internal/transport ./apps/daemon/internal/dispatch ./apps/daemon/internal/wireconformance -count=1 go test ./services/core/internal/execution -run '^TestRuntimeProtocol' -count=1 go test ./apps/daemon/internal/agent/... -run '^(TestSharedTextLifecycle|TestPublicHarnessContractDeclarations|TestRegistryRejectsEveryOmittedCapabilityBeforeReplacement|TestUnsupportedExtensionsHaveNoNativeEffects)$$' -count=1 diff --git a/apps/daemon/internal/wireconformance/wire_test.go b/apps/daemon/internal/wireconformance/wire_test.go new file mode 100644 index 000000000..328737c23 --- /dev/null +++ b/apps/daemon/internal/wireconformance/wire_test.go @@ -0,0 +1,371 @@ +// Package wireconformance runs the Runtime's production transport and +// dispatcher, with a controlled Harness adapter, against a scripted Core that +// replays the Core frames of the shared wire scenarios. +package wireconformance + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "strings" + "sync" + "sync/atomic" + "testing" + "time" + + "github.com/gorilla/websocket" + + "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/agent" + "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/dispatch" + "github.com/MiniMax-AI/OpenAgentCore/apps/daemon/internal/transport" + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" + "github.com/MiniMax-AI/OpenAgentCore/internal/harnessconfig" +) + +const wait = 3 * time.Second + +// corePeer is the scripted Core. It accepts the shared handshake and rejects +// any other protocol version as Core does. +type corePeer struct { + endpoint string + conns chan *websocket.Conn + frames chan proto.Envelope + ws *websocket.Conn + bindings prototest.Bindings +} + +func newCorePeer(t *testing.T) *corePeer { + t.Helper() + p := &corePeer{conns: make(chan *websocket.Conn, 4), bindings: prototest.Bindings{}} + var upgrader websocket.Upgrader + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + if query.Get("device_id") != prototest.DeviceID || r.Header.Get("Authorization") != "Bearer "+prototest.Credential || strings.Contains(r.URL.RawQuery, prototest.Credential) { + t.Errorf("Runtime handshake: device %q, bearer credential %t, credential in URL %t", query.Get("device_id"), r.Header.Get("Authorization") == "Bearer "+prototest.Credential, strings.Contains(r.URL.RawQuery, prototest.Credential)) + w.WriteHeader(http.StatusUnauthorized) + return + } + if query.Get("version") != proto.Version { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(prototest.IncompatibleVersionStatus) + _ = json.NewEncoder(w).Encode(map[string]string{"error": prototest.IncompatibleVersionCode}) + return + } + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + t.Errorf("upgrade: %v", err) + return + } + p.conns <- ws + })) + t.Cleanup(server.Close) + p.endpoint = "ws" + strings.TrimPrefix(server.URL, "http") + return p +} + +// accept takes the Runtime's next connection. +func (p *corePeer) accept(t *testing.T) { + t.Helper() + select { + case ws := <-p.conns: + t.Cleanup(func() { ws.Close() }) + frames := make(chan proto.Envelope, 16) + go func() { + defer close(frames) + for { + var env proto.Envelope + if ws.ReadJSON(&env) != nil { + return + } + frames <- env + } + }() + p.ws, p.frames = ws, frames + case <-time.After(wait): + t.Fatal("Runtime did not connect") + } +} + +func (p *corePeer) receive(t *testing.T) proto.Envelope { + t.Helper() + select { + case env, ok := <-p.frames: + if !ok { + t.Fatal("Runtime closed the connection") + } + return env + case <-time.After(wait): + t.Fatal("no frame from the Runtime") + } + return proto.Envelope{} +} + +func (p *corePeer) silent(t *testing.T, reason string) { + t.Helper() + select { + case env, ok := <-p.frames: + if ok { + t.Fatalf("Runtime sent %s %q %s", env.Type, env.ID, reason) + } + t.Fatalf("Runtime closed the connection %s", reason) + case <-time.After(prototest.SilenceWindow): + } +} + +func dial(t *testing.T, endpoint, version string) (*transport.Conn, error) { + t.Helper() + ctx, cancel := context.WithTimeout(t.Context(), wait) + defer cancel() + return transport.Dial(ctx, transport.DialOptions{WSURL: endpoint, DeviceID: prototest.DeviceID, Credential: prototest.Credential, DaemonVersion: version}) +} + +func TestWireRejectsIncompatibleVersions(t *testing.T) { + peer := newCorePeer(t) + for _, version := range prototest.IncompatibleVersions() { + t.Run(version, func(t *testing.T) { + attempts := 0 + _, err := transport.Reconnect(t.Context(), func(context.Context) (*transport.Conn, error) { + attempts++ + return dial(t, peer.endpoint, version) + }, transport.DefaultBackoff, nil) + if !errors.Is(err, transport.ErrIncompatibleVersion) || !errors.Is(err, transport.ErrPermanent) || attempts != 1 { + t.Fatalf("mismatch must stop after one attempt: attempts=%d error=%v", attempts, err) + } + }) + } +} + +// runtimeSide is the production transport and dispatcher with a controlled adapter. +type runtimeSide struct { + conn *transport.Conn + executor *controlledExecutor + turn *controlledTurn + started int32 + stopped chan struct{} + shutdownErr error +} + +func connectRuntime(t *testing.T, peer *corePeer, setupErr error) *runtimeSide { + t.Helper() + conn, err := dial(t, peer.endpoint, proto.Version) + if err != nil { + t.Fatal(err) + } + peer.accept(t) + rt := &runtimeSide{conn: conn, executor: &controlledExecutor{turn: make(chan *controlledTurn, 1)}, stopped: make(chan struct{})} + kinds := agent.NewRegistry() + kinds.RegisterKind(proto.SupportedAgentKind{Kind: prototest.HarnessKind, Available: true, Capabilities: prototest.Capabilities(proto.AgentKindCapabilities{EnvironmentNone: proto.CapabilitySupported})}, + harnessconfig.Configuration{}, func(context.Context, proto.PromptRequestPayload, chan<- proto.Envelope) (agent.Session, error) { + return nil, errors.New("prepared execution must not use prompt_request") + }) + kinds.RegisterExecutor(prototest.HarnessKind, func(context.Context, proto.PromptRequestPayload) (agent.Executor, error) { + return rt.executor, setupErr + }) + router, err := dispatch.New(dispatch.Config{Registry: kinds, Sender: conn}) + if err != nil { + t.Fatal(err) + } + go func() { + for env := range conn.Recv() { + if err := router.Handle(t.Context(), env); err != nil { + t.Errorf("dispatch: %v", err) + } + } + ctx, cancel := context.WithTimeout(context.Background(), wait) + defer cancel() + rt.shutdownErr = router.Shutdown(ctx) + close(rt.stopped) + }() + t.Cleanup(func() { + if rt.turn == nil { + select { + case rt.turn = <-rt.executor.turn: + default: + } + } + if rt.turn != nil { + rt.turn.release() + } + conn.Close() + select { + case <-rt.stopped: + if rt.shutdownErr != nil { + t.Error(rt.shutdownErr) + } + case <-time.After(wait + time.Second): + t.Error("Runtime shutdown did not complete") + } + }) + return rt +} + +func TestWireScenarios(t *testing.T) { + for _, scenario := range prototest.WireScenarios() { + t.Run(scenario.Name, func(t *testing.T) { + var setupErr error + if scenario.NativeSetupFails { + setupErr = errors.New("native setup failed") + } + peer := newCorePeer(t) + rt := connectRuntime(t, peer, setupErr) + for _, step := range scenario.Steps { + switch step.Action { + case prototest.Send: + if step.From == prototest.Core { + frame, err := peer.bindings.Resolve(step.Frame) + if err != nil { + t.Fatal(err) + } + if err := peer.ws.WriteJSON(frame); err != nil { + t.Fatal(err) + } + } else { + if err := peer.bindings.Match(step.Frame, peer.receive(t)); err != nil { + t.Fatal(err) + } + rt.reported(t, step.Frame) + } + case prototest.Silence: + // Core's silence needs nothing from the Runtime. + if step.From == prototest.Runtime { + peer.silent(t, "after its last scenario frame") + } + case prototest.Settle: + rt.settle(t, peer) + case prototest.Disconnect: + rt.disconnect(t, peer) + case prototest.Reconnect: + conn, err := dial(t, peer.endpoint, proto.Version) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { conn.Close() }) + peer.accept(t) + } + } + if starts := rt.executor.starts.Load(); starts != rt.started { + t.Fatalf("native input submitted %d times for %d started Turns", starts, rt.started) + } + }) + } +} + +// reported checks the native state behind a preparation status the Runtime sent. +func (rt *runtimeSide) reported(t *testing.T, frame proto.Envelope) { + t.Helper() + if frame.Type != proto.TypePreparationStatus { + return + } + var status proto.PreparationStatusPayload + if err := frame.DecodePayload(&status); err != nil { + t.Fatal(err) + } + switch status.State { + case "preparing", "ready": + if rt.executor.starts.Load() != rt.started { + t.Fatal("preparation submitted input") + } + case "failed": + if rt.executor.starts.Load() != rt.started || rt.executor.closes.Load() != 1 { + t.Fatalf("failed preparation retained resources or started input: starts=%d closes=%d", rt.executor.starts.Load(), rt.executor.closes.Load()) + } + case "started": + select { + case rt.turn = <-rt.executor.turn: + rt.started++ + case <-time.After(wait): + t.Fatal("no native turn") + } + } +} + +// settle holds native cancellation until the Runtime has stayed silent. +func (rt *runtimeSide) settle(t *testing.T, peer *corePeer) { + t.Helper() + select { + case <-rt.turn.cancelling: + case <-time.After(wait): + t.Fatal("cancellation was not received") + } + peer.silent(t, "before native settlement") + rt.turn.release() +} + +// disconnect loses the connection after work started; cleanup still settles. +func (rt *runtimeSide) disconnect(t *testing.T, peer *corePeer) { + t.Helper() + if rt.turn != nil { + rt.turn.release() + } + rt.conn.Close() + select { + case <-rt.stopped: + if rt.shutdownErr != nil || rt.executor.closes.Load() != 1 { + t.Fatalf("disconnect cleanup: %v, closes=%d", rt.shutdownErr, rt.executor.closes.Load()) + } + case <-time.After(wait): + t.Fatal("disconnect cleanup did not settle") + } + select { + case env, ok := <-peer.frames: + if ok { + t.Fatalf("lost connection carried %s %q", env.Type, env.ID) + } + case <-time.After(wait): + t.Fatal("lost connection stayed open") + } +} + +type controlledExecutor struct { + turn chan *controlledTurn + starts atomic.Int32 + closes atomic.Int32 +} + +func (e *controlledExecutor) Close(context.Context) error { e.closes.Add(1); return nil } +func (e *controlledExecutor) StartTurn(_ context.Context, id string, _ proto.MessageInput, out chan<- proto.Envelope) (agent.Turn, error) { + e.starts.Add(1) + turn := &controlledTurn{id: id, out: out, cancelling: make(chan struct{}), allowCancel: make(chan struct{}), settled: make(chan struct{})} + e.turn <- turn + return turn, nil +} + +type controlledTurn struct { + id string + out chan<- proto.Envelope + cancelling, allowCancel, settled chan struct{} + cancelOnce, finishOnce, releaseOnce sync.Once +} + +// release lets a pending native cancellation settle. +func (turn *controlledTurn) release() { turn.releaseOnce.Do(func() { close(turn.allowCancel) }) } + +func (turn *controlledTurn) Cancel(ctx context.Context) error { + turn.cancelOnce.Do(func() { close(turn.cancelling) }) + select { + case <-turn.allowCancel: + turn.finishOnce.Do(func() { close(turn.out); close(turn.settled) }) + return nil + case <-ctx.Done(): + return ctx.Err() + } +} +func (turn *controlledTurn) CancellationOutcome() proto.DonePayload { + return prototest.CancellationOutcome() +} +func (turn *controlledTurn) AwaitSettlement(ctx context.Context) (agent.TurnSettlement, error) { + select { + case <-turn.settled: + return agent.TurnSettlement{Reason: "cancelled fixture"}, nil + case <-ctx.Done(): + return agent.TurnSettlement{}, ctx.Err() + } +} + +// These fixtures exercise settlement only; active input is deliberately rejected. +func (*controlledTurn) SteerWithReceipt(context.Context, proto.PromptSteerPayload, func()) error { + return agent.ErrSteeringRejected +} diff --git a/docs/runtime-protocol.md b/docs/runtime-protocol.md index ca03a782d..f11e5413b 100644 --- a/docs/runtime-protocol.md +++ b/docs/runtime-protocol.md @@ -199,8 +199,10 @@ Every public `MCPHTTPServer` in a prompt request carries an explicit `connection ## Contract verification -Run `make check-runtime-contract` from the repository root. It exercises the shared wire validators, gateway, transport and dispatcher, the [real WebSocket contract scenarios](../apps/daemon/internal/contracttest/wire_test.go) with a controlled Harness adapter, the [observation-result regression](../services/core/internal/execution/runtime_protocol_test.go) and the Harness declaration tests. It needs no model credentials or external sandbox, and `make check` runs the same tests through `check-go` and `check-core`. +Run `make check-runtime-contract` from the repository root. It exercises the shared wire validators, gateway, transport and dispatcher, the shared wire scenarios on both sides, the [observation-result regression](../services/core/internal/execution/runtime_protocol_test.go) and the Harness declaration tests. It needs no model credentials or external sandbox, and `make check` runs the same tests through `check-go` and `check-core`. + +Each [wire scenario](../internal/agentdaemon/proto/prototest/wire.go) lists once, in order, the frames Core and the Runtime send, together with native settlement, connection loss and reconnection. Each side runs its real implementation against a scripted peer that replays the other side's frames over a WebSocket: [Core's gateway test](../services/core/internal/runtimegateway/wire_test.go) and the [Runtime's transport and dispatcher test](../apps/daemon/internal/wireconformance/wire_test.go), which uses a controlled Harness adapter. Each side asserts the frames it sends and the behavior it owns; neither imports the other. Values the Runtime generates, such as the Executor ID, admission handle and expiry, are placeholders that the Runtime side binds to the values its Runtime sends. The suite covers incompatible versions, preparation failure, cancellation settlement, connection loss without invented terminal events, reconnection without replay, stale or duplicate handles and receipts, cleanup failures, bounded transfer validation and resource ownership after a timeout. Detailed fault injection stays next to the gateway and dispatcher code it tests. -Another Runtime reuses these protocol sequences and assertions, then runs native acceptance for every capability it declares. A controlled-adapter test establishes the transport contract, not native Harness behavior, operating-system support, provider authentication or sandbox isolation. Change the shared types, this document and the contract checks together. Harness adapters also run the shared text assertions described in [Harness onboarding](../contracts/agents-api/harness-onboarding.md). +Another Runtime replays the same scenarios against a scripted Core, then runs native acceptance for every capability it declares. A controlled-adapter test establishes the transport contract, not native Harness behavior, operating-system support, provider authentication or sandbox isolation. Change the shared types, this document and the contract checks together. Harness adapters also run the shared text assertions described in [Harness onboarding](../contracts/agents-api/harness-onboarding.md). diff --git a/internal/agentdaemon/proto/prototest/capabilities.go b/internal/agentdaemon/proto/prototest/capabilities.go index 8028d9b6c..f40726262 100644 --- a/internal/agentdaemon/proto/prototest/capabilities.go +++ b/internal/agentdaemon/proto/prototest/capabilities.go @@ -1,4 +1,5 @@ -// Package prototest provides explicit capability fixtures for contract tests. +// Package prototest provides explicit capability fixtures and the shared wire +// scenarios for Core–Runtime contract tests. package prototest import ( diff --git a/internal/agentdaemon/proto/prototest/wire.go b/internal/agentdaemon/proto/prototest/wire.go new file mode 100644 index 000000000..d27120aad --- /dev/null +++ b/internal/agentdaemon/proto/prototest/wire.go @@ -0,0 +1,261 @@ +package prototest + +import ( + "encoding/json" + "fmt" + "net/http" + "reflect" + "slices" + "time" + + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" +) + +// Wire scenarios define each Core–Runtime exchange once. Core's gateway test +// replays the Runtime frames against the real gateway, and the Runtime test +// replays the Core frames against the real transport and dispatcher. Each side +// asserts the frames it must send and the behavior it owns. + +// Handshake values. The Runtime dials with DeviceID and Credential; Core +// accepts that credential for DeviceID. +const ( + DeviceID = "runtime" + Credential = "synthetic-contract-credential" + HarnessKind = "contract" +) + +// Correlation values the scenarios use. +const ( + SessionID = "session" + StateKey = "agents-api-session" + PreparationID = "prepare" + RunID = "run" + CancelDeliveryID = "cancel" +) + +// Placeholders for values the Runtime generates. Core's side sends them as +// written; the Runtime's side binds each to the value its Runtime sends. +const ( + ExecutorID = "executor" + Handle = "handle" + ExpiresAt int64 = 1_800_000_000_000 +) + +// Core rejects any other protocol version at the upgrade with this status and +// error code, before any dispatch. +const ( + IncompatibleVersionStatus = http.StatusUpgradeRequired + IncompatibleVersionCode = "incompatible_version" +) + +// SilenceWindow is how long a Silence or Settle step waits for an unexpected frame. +const SilenceWindow = 50 * time.Millisecond + +// IncompatibleVersions are Runtime protocol versions Core rejects. +func IncompatibleVersions() []string { + return []string{"0.7.0", "0.8.99", "0.8.", proto.Version + "-dev", proto.Version + "+build"} +} + +// Peer is one side of the connection. +type Peer string + +const ( + Core Peer = "Core" + Runtime Peer = "Runtime" +) + +// Action is what happens at one scenario step. +type Action int + +const ( + // Send: From sends Frame, and the other side receives it next. + Send Action = iota + // Silence: From sends nothing for SilenceWindow. + Silence + // Settle: the Runtime's native work settles. The Runtime sends nothing + // before that, so no receipt precedes native settlement. + Settle + // Disconnect: the Runtime loses the connection while work runs. The Runtime + // settles its native work and cleanup; Core observes no execution outcome. + Disconnect + // Reconnect: the Runtime connects again with the same device identity. + Reconnect +) + +// Step is one scenario step. From and Frame apply to Send; From applies to Silence. +type Step struct { + Action Action + From Peer + Frame proto.Envelope +} + +// WireScenario is one ordered exchange. +type WireScenario struct { + Name string + // NativeSetupFails makes the Runtime's native Executor setup fail. + NativeSetupFails bool + Steps []Step +} + +// CancellationOutcome is the continuity snapshot a cancelled Turn reports. +func CancellationOutcome() proto.DonePayload { + return proto.DonePayload{Content: "partial", Metadata: map[string]any{proto.DoneMetaAgentSessionID: "native-session"}} +} + +// WireScenarios returns every shared exchange. +func WireScenarios() []WireScenario { + input := proto.TextInput("hello") + if err := input.Validate(); err != nil { + panic(err) + } + prepare := send(Core, proto.TypeExecutionPrepare, PreparationID, proto.ExecutionPreparePayload{ + SessionID: SessionID, + Configuration: proto.PromptRequestPayload{AgentKind: HarnessKind, AgentStateKey: StateKey, StrictResume: true, DisableExecutionEnvironment: true}, + }) + started := []Step{ + prepare, + status(1, "preparing", "", ""), + status(2, "ready", "", ""), + send(Core, proto.TypeExecutionStart, PreparationID, proto.ExecutionStartPayload{ExecutorID: ExecutorID, Handle: Handle, RunID: RunID, Input: input}), + status(3, "starting", RunID, ""), + status(4, "started", RunID, ""), + } + outcome := CancellationOutcome() + return []WireScenario{ + { + Name: "cancellation_waits_for_settlement", + Steps: append(slices.Clone(started), + send(Core, proto.TypePromptCancel, RunID, proto.PromptCancelPayload{DeliveryID: CancelDeliveryID}), + Step{Action: Settle}, + send(Runtime, proto.TypeDone, RunID, proto.DonePayload{}), + send(Runtime, proto.TypeInteractionDecisionAck, RunID, proto.InteractionDecisionAckPayload{DeliveryID: CancelDeliveryID, Applied: true, Outcome: &outcome}), + ), + }, + { + Name: "preparation_failure_cleans_up_without_run_completion", + NativeSetupFails: true, + Steps: []Step{ + prepare, + status(1, "preparing", "", ""), + status(2, "failed", "", "preparation_failed"), + {Action: Silence, From: Runtime}, + }, + }, + { + Name: "disconnect_is_unknown_and_reconnect_does_not_replay", + Steps: append(slices.Clone(started), + Step{Action: Disconnect}, + Step{Action: Reconnect}, + Step{Action: Silence, From: Core}, + ), + }, + } +} + +func send(from Peer, kind, id string, payload any) Step { + frame, err := proto.NewEnvelope(kind, id, payload) + if err != nil { + panic(err) + } + return Step{Action: Send, From: from, Frame: frame} +} + +func status(revision uint64, state, runID, errorCode string) Step { + return send(Runtime, proto.TypePreparationStatus, PreparationID, proto.PreparationStatusPayload{ + ExecutorID: ExecutorID, Handle: Handle, Revision: revision, State: state, ExpiresAt: ExpiresAt, RunID: runID, ErrorCode: errorCode, + }) +} + +// SameFrame checks that got carries want's type, correlation ID and payload. +// Trace is diagnostic correlation and is not part of a scenario. +func SameFrame(want, got proto.Envelope) error { + return Bindings{}.match(want, got, false) +} + +// runtimeAssigned lists the payload fields whose values the Runtime generates. +var runtimeAssigned = []string{"executor_id", "handle", "expires_at"} + +// Bindings maps each placeholder to the value the Runtime under test sent for it. +type Bindings map[string]any + +// Match checks that got is want's frame. A Runtime-assigned field binds its +// placeholder to the first non-empty value the Runtime sends; later frames must +// repeat that value. +func (b Bindings) Match(want, got proto.Envelope) error { + return b.match(want, got, true) +} + +func (b Bindings) match(want, got proto.Envelope, bind bool) error { + wantFields, err := fields(want) + if err != nil { + return err + } + gotFields, err := fields(got) + if err != nil { + return err + } + bound := map[string]any{} + if bind { + for _, field := range runtimeAssigned { + placeholder, ok := wantFields[field] + if !ok { + continue + } + key := bindingKey(field, placeholder) + value, ok := b[key] + if !ok { + value = gotFields[field] + if value == nil || reflect.ValueOf(value).IsZero() { + return fmt.Errorf("%s frame lacks Runtime-assigned %s", got.Type, field) + } + bound[key] = value + } + wantFields[field] = value + } + } + if want.Type != got.Type || want.ID != got.ID || !reflect.DeepEqual(wantFields, gotFields) { + return fmt.Errorf("got %s %q %s, want %s %q %s", got.Type, got.ID, got.Payload, want.Type, want.ID, want.Payload) + } + for key, value := range bound { + b[key] = value + } + return nil +} + +// Resolve replaces bound placeholders in a Core frame with the Runtime's values. +func (b Bindings) Resolve(frame proto.Envelope) (proto.Envelope, error) { + payload, err := fields(frame) + if err != nil { + return proto.Envelope{}, err + } + changed := false + for _, field := range runtimeAssigned { + if placeholder, ok := payload[field]; ok { + if value, ok := b[bindingKey(field, placeholder)]; ok { + payload[field], changed = value, true + } + } + } + if !changed { + return frame, nil + } + if frame.Payload, err = json.Marshal(payload); err != nil { + return proto.Envelope{}, err + } + return frame, nil +} + +func fields(frame proto.Envelope) (map[string]any, error) { + out := map[string]any{} + if len(frame.Payload) == 0 { + return out, nil + } + if err := json.Unmarshal(frame.Payload, &out); err != nil { + return nil, fmt.Errorf("%s frame payload: %w", frame.Type, err) + } + return out, nil +} + +func bindingKey(field string, placeholder any) string { + return fmt.Sprint(field, "=", placeholder) +} diff --git a/internal/agentdaemon/proto/prototest/wire_test.go b/internal/agentdaemon/proto/prototest/wire_test.go new file mode 100644 index 000000000..c98cba861 --- /dev/null +++ b/internal/agentdaemon/proto/prototest/wire_test.go @@ -0,0 +1,35 @@ +package prototest + +import ( + "testing" + + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" +) + +func TestBindingsBindRuntimeValuesOnce(t *testing.T) { + ready := status(2, "ready", "", "").Frame + sent := func(handle string, revision uint64) proto.Envelope { + return send(Runtime, proto.TypePreparationStatus, PreparationID, proto.PreparationStatusPayload{ExecutorID: "e-1", Handle: handle, Revision: revision, State: "ready", ExpiresAt: 7}).Frame + } + b := Bindings{} + if err := b.Match(ready, sent("h-1", 3)); err == nil { + t.Fatal("a payload difference matched") + } + if len(b) != 0 { + t.Fatal("a failed match bound values") + } + if err := b.Match(ready, sent("h-1", 2)); err != nil { + t.Fatal(err) + } + if err := b.Match(ready, sent("h-2", 2)); err == nil { + t.Fatal("a bound placeholder accepted another value") + } + start, err := b.Resolve(send(Core, proto.TypeExecutionStart, PreparationID, proto.ExecutionStartPayload{ExecutorID: ExecutorID, Handle: Handle, RunID: RunID}).Frame) + var payload proto.ExecutionStartPayload + if err != nil || start.DecodePayload(&payload) != nil || payload.ExecutorID != "e-1" || payload.Handle != "h-1" || payload.RunID != RunID { + t.Fatalf("resolved start: %s %v", start.Payload, err) + } + if SameFrame(ready, sent("h-1", 2)) == nil { + t.Fatal("SameFrame bound a placeholder") + } +} diff --git a/scripts/name-allowlist.json b/scripts/name-allowlist.json index 7db5451fd..f041300b5 100644 --- a/scripts/name-allowlist.json +++ b/scripts/name-allowlist.json @@ -249,6 +249,11 @@ "regex": "\"agents-api-\"", "reason": "AgentStateKey retains the existing daemon/native-session resume identity; capability snapshots bind to the Session UUID carried in that identity." }, + { + "path": "internal/agentdaemon/proto/prototest/wire.go", + "regex": "agents-api-session", + "reason": "The shared wire scenarios use the existing Core Session state-key prefix required by execution admission." + }, { "path": "apps/daemon/internal/agent/mcode/tool_environment_test.go", "regex": "agents-api-", diff --git a/services/core/internal/runtimegateway/wire_test.go b/services/core/internal/runtimegateway/wire_test.go new file mode 100644 index 000000000..a3b4acb64 --- /dev/null +++ b/services/core/internal/runtimegateway/wire_test.go @@ -0,0 +1,361 @@ +package runtimegateway_test + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "net/url" + "reflect" + "strings" + "testing" + "time" + + "github.com/gorilla/websocket" + + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto" + "github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto/prototest" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimedevice" + "github.com/MiniMax-AI/OpenAgentCore/services/core/internal/runtimegateway" +) + +// These tests run Core's gateway against a scripted Runtime that replays the +// Runtime frames of the shared wire scenarios. + +const wait = 3 * time.Second + +type credentialStore struct{} + +func (credentialStore) GetDeviceCredential(context.Context, string) (runtimedevice.Credential, bool, error) { + return runtimedevice.Credential{ID: prototest.DeviceID, WorkspaceID: "tenant", Type: runtimegateway.RuntimeTypeAgentDaemon, CredentialHash: runtimedevice.HashCredential(prototest.Credential)}, true, nil +} + +func newGateway(t *testing.T) (*runtimegateway.Registry, string) { + t.Helper() + reg := runtimegateway.NewRegistry() + handler := runtimegateway.NewHandler(runtimegateway.HandlerConfig{Registry: reg, Authenticator: runtimegateway.NewAuthenticator(credentialStore{})}) + server := httptest.NewServer(http.HandlerFunc(handler.WS)) + t.Cleanup(server.Close) + return reg, "ws" + strings.TrimPrefix(server.URL, "http") +} + +// runtimePeer is the scripted Runtime end of one connection. +type runtimePeer struct { + ws *websocket.Conn + frames chan proto.Envelope +} + +func dialRuntime(t *testing.T, endpoint, version string) (*runtimePeer, *http.Response, error) { + t.Helper() + ctx, cancel := context.WithTimeout(t.Context(), wait) + defer cancel() + query := url.Values{"device_id": {prototest.DeviceID}, "version": {version}} + ws, response, err := websocket.DefaultDialer.DialContext(ctx, endpoint+"?"+query.Encode(), http.Header{"Authorization": {"Bearer " + prototest.Credential}}) + if err != nil { + return nil, response, err + } + t.Cleanup(func() { ws.Close() }) + peer := &runtimePeer{ws: ws, frames: make(chan proto.Envelope, 16)} + go func() { + defer close(peer.frames) + for { + var env proto.Envelope + if ws.ReadJSON(&env) != nil { + return + } + peer.frames <- env + } + }() + return peer, response, nil +} + +func (p *runtimePeer) receive(t *testing.T) proto.Envelope { + t.Helper() + select { + case env, ok := <-p.frames: + if !ok { + t.Fatal("Core closed the connection") + } + return env + case <-time.After(wait): + t.Fatal("no frame from Core") + } + return proto.Envelope{} +} + +func (p *runtimePeer) silent(t *testing.T) { + t.Helper() + select { + case env, ok := <-p.frames: + if !ok { + t.Fatal("Core closed the connection") + } + t.Fatalf("Core sent %s %q; reconnect must not replay work", env.Type, env.ID) + case <-time.After(prototest.SilenceWindow): + } +} + +type receipt struct { + ack proto.InteractionDecisionAckPayload + err error +} + +// coreSide drives the gateway the way Core's execution layer does. +type coreSide struct { + t *testing.T + reg *runtimegateway.Registry + endpoint string + session *runtimegateway.Session + peer *runtimePeer + preparations map[string]*runtimegateway.Subscription + runs map[string]*runtimegateway.Subscription + receipts map[string]chan receipt +} + +func (c *coreSide) connect() { + c.t.Helper() + peer, _, err := dialRuntime(c.t, c.endpoint, proto.Version) + if err != nil { + c.t.Fatal(err) + } + session, err := c.reg.WaitForDevice(c.t.Context(), prototest.DeviceID, wait) + if err != nil { + c.t.Fatal(err) + } + c.t.Cleanup(func() { session.Close("test finished") }) + c.peer, c.session = peer, session +} + +func TestWireRejectsIncompatibleVersions(t *testing.T) { + reg, endpoint := newGateway(t) + for _, version := range prototest.IncompatibleVersions() { + t.Run(version, func(t *testing.T) { + _, response, err := dialRuntime(t, endpoint, version) + if err == nil || response == nil || response.StatusCode != prototest.IncompatibleVersionStatus { + t.Fatalf("upgrade with version %q: %v", version, err) + } + var body struct { + Error string `json:"error"` + } + if json.NewDecoder(response.Body).Decode(&body) != nil || body.Error != prototest.IncompatibleVersionCode { + t.Fatalf("rejection code %q", body.Error) + } + if devices := reg.Devices(); len(devices) != 0 { + t.Fatalf("rejected connection registered %v", devices) + } + }) + } +} + +func TestWireScenarios(t *testing.T) { + for _, scenario := range prototest.WireScenarios() { + t.Run(scenario.Name, func(t *testing.T) { + reg, endpoint := newGateway(t) + c := &coreSide{t: t, reg: reg, endpoint: endpoint, preparations: map[string]*runtimegateway.Subscription{}, runs: map[string]*runtimegateway.Subscription{}, receipts: map[string]chan receipt{}} + c.connect() + // Subscribing before any frame also observes that a failed + // preparation produces no Run result. + run, err := c.session.SubscribeDurable(prototest.RunID) + if err != nil { + t.Fatal(err) + } + c.runs[prototest.RunID] = run + for _, step := range scenario.Steps { + switch step.Action { + case prototest.Send: + if step.From == prototest.Core { + c.coreSends(step.Frame) + } else { + c.runtimeSends(step.Frame) + } + case prototest.Silence: + if step.From == prototest.Core { + c.peer.silent(t) + } else { + c.noRunOutput() + } + case prototest.Settle: + c.receiptsPending() + case prototest.Disconnect: + c.disconnect() + case prototest.Reconnect: + c.reconnect() + } + } + }) + } +} + +// coreSends sends a Core frame the way execution does and checks that the +// Runtime receives it unchanged. +func (c *coreSide) coreSends(frame proto.Envelope) { + t := c.t + t.Helper() + switch frame.Type { + case proto.TypeExecutionPrepare: + sub, err := c.session.SubscribePreparation(frame.ID) + if err != nil { + t.Fatal(err) + } + c.preparations[frame.ID] = sub + c.send(frame) + case proto.TypePromptCancel: + var request proto.PromptCancelPayload + if err := frame.DecodePayload(&request); err != nil { + t.Fatal(err) + } + done := make(chan receipt, 1) + c.receipts[request.DeliveryID] = done + go func() { + ack, err := c.session.SendAndWaitInteractionAck(t.Context(), frame, request.DeliveryID) + done <- receipt{ack, err} + }() + default: + c.send(frame) + } + if err := prototest.SameFrame(frame, c.peer.receive(t)); err != nil { + t.Fatal(err) + } +} + +func (c *coreSide) send(frame proto.Envelope) { + c.t.Helper() + ctx, cancel := context.WithTimeout(c.t.Context(), wait) + defer cancel() + if err := c.session.Send(ctx, frame); err != nil { + c.t.Fatal(err) + } +} + +// runtimeSends replays a Runtime frame and checks where Core delivers it. +func (c *coreSide) runtimeSends(frame proto.Envelope) { + t := c.t + t.Helper() + switch frame.Type { + case proto.TypeInteractionDecisionAck: + var want proto.InteractionDecisionAckPayload + if err := frame.DecodePayload(&want); err != nil { + t.Fatal(err) + } + done := c.receipts[want.DeliveryID] + if done == nil { + t.Fatalf("no pending receipt for %q", want.DeliveryID) + } + select { + case got := <-done: + t.Fatalf("receipt returned before the Runtime sent it: %+v, %v", got.ack, got.err) + default: + } + c.write(frame) + select { + case got := <-done: + if got.err != nil || !reflect.DeepEqual(got.ack, want) { + t.Fatalf("receipt %+v, %v; want %+v", got.ack, got.err, want) + } + case <-time.After(wait): + t.Fatal("missing receipt") + } + delete(c.receipts, want.DeliveryID) + case proto.TypePreparationStatus: + c.write(frame) + c.delivered(c.preparations[frame.ID], frame) + default: + c.write(frame) + c.delivered(c.runs[frame.ID], frame) + } +} + +func (c *coreSide) write(frame proto.Envelope) { + c.t.Helper() + if err := c.peer.ws.WriteJSON(frame); err != nil { + c.t.Fatal(err) + } +} + +func (c *coreSide) delivered(sub *runtimegateway.Subscription, frame proto.Envelope) { + t := c.t + t.Helper() + if sub == nil { + t.Fatalf("no subscription for %s %q", frame.Type, frame.ID) + } + select { + case env, ok := <-sub.Events: + if !ok { + t.Fatalf("subscription closed: %v", sub.Err()) + } + if err := prototest.SameFrame(frame, env); err != nil { + t.Fatal(err) + } + case <-time.After(wait): + t.Fatalf("%s %q was not delivered", frame.Type, frame.ID) + } +} + +func (c *coreSide) noRunOutput() { + c.t.Helper() + timeout := time.After(prototest.SilenceWindow) + for runID, sub := range c.runs { + select { + case env, ok := <-sub.Events: + c.t.Fatalf("Run %q received %s (open=%t) without Runtime output", runID, env.Type, ok) + case <-timeout: + } + } +} + +func (c *coreSide) receiptsPending() { + c.t.Helper() + timeout := time.After(prototest.SilenceWindow) + for id, done := range c.receipts { + select { + case got := <-done: + c.t.Fatalf("receipt %q preceded native settlement: %+v, %v", id, got.ack, got.err) + case <-timeout: + } + } +} + +func (c *coreSide) disconnect() { + t := c.t + t.Helper() + c.peer.ws.Close() + select { + case <-c.session.Closed(): + case <-time.After(wait): + t.Fatal("gateway stayed connected") + } + for runID, sub := range c.runs { + for env := range sub.Events { + if env.Type == proto.TypeError || env.Type == proto.TypeDone { + t.Fatalf("disconnect manufactured %s for Run %q", env.Type, runID) + } + } + if !errors.Is(sub.Err(), runtimegateway.ErrSessionClosed) { + t.Fatalf("Run %q disconnect outcome: %v", runID, sub.Err()) + } + } + for deadline := time.Now().Add(wait); ; time.Sleep(time.Millisecond) { + if _, err := c.reg.LookupDevice(prototest.DeviceID); errors.Is(err, runtimegateway.ErrDeviceNotRegistered) { + break + } + if time.Now().After(deadline) { + t.Fatal("lost connection stayed registered") + } + } +} + +func (c *coreSide) reconnect() { + t := c.t + t.Helper() + previous := c.session + c.connect() + if c.session == previous { + t.Fatal("reconnect reused the lost connection") + } + for runID := range c.runs { + if c.reg.LookupRun(runID) != nil { + t.Fatalf("reconnect inherited Run %q", runID) + } + } +}