Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
66 changes: 33 additions & 33 deletions contracts/agents-api/core.openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ definitions:
$ref: '#/definitions/api.ExecutorConnection'
data:
items:
$ref: '#/definitions/store.ExecutorCredential'
$ref: '#/definitions/sessions.ExecutorCredential'
type: array
required:
- connection
Expand Down Expand Up @@ -1335,33 +1335,7 @@ definitions:
source_commit:
type: string
type: object
store.AddressBindings:
properties:
hosted_sandboxes:
type: integer
nodes:
type: integer
nodes_on_other_address:
type: integer
self_hosted_executors:
type: integer
type: object
store.AdminAssetCounts:
properties:
agents:
type: integer
credentials:
type: integer
environment_templates:
type: integer
files:
type: integer
skills:
type: integer
vaults:
type: integer
type: object
store.ExecutorCredential:
sessions.ExecutorCredential:
properties:
created_at:
type: string
Expand All @@ -1372,7 +1346,7 @@ definitions:
type: string
x-nullable: true
type: object
store.IssuedExecutorCredential:
sessions.IssuedExecutorCredential:
properties:
environment_id:
type: string
Expand All @@ -1381,7 +1355,7 @@ definitions:
key_id:
type: string
type: object
store.ManagedSessionArchive:
sessions.ManagedArchive:
properties:
environment_id:
type: string
Expand All @@ -1390,6 +1364,32 @@ definitions:
state:
type: string
type: object
store.AddressBindings:
properties:
hosted_sandboxes:
type: integer
nodes:
type: integer
nodes_on_other_address:
type: integer
self_hosted_executors:
type: integer
type: object
store.AdminAssetCounts:
properties:
agents:
type: integer
credentials:
type: integer
environment_templates:
type: integer
files:
type: integer
skills:
type: integer
vaults:
type: integer
type: object
store.RuntimeNodeAllocation:
properties:
compute_phase:
Expand Down Expand Up @@ -4162,7 +4162,7 @@ paths:
"201":
description: Created
schema:
$ref: '#/definitions/store.IssuedExecutorCredential'
$ref: '#/definitions/sessions.IssuedExecutorCredential'
"400":
description: Bad Request
schema:
Expand Down Expand Up @@ -4771,7 +4771,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/store.ManagedSessionArchive'
$ref: '#/definitions/sessions.ManagedArchive'
"400":
description: Bad Request
schema:
Expand Down Expand Up @@ -4824,7 +4824,7 @@ paths:
"200":
description: OK
schema:
$ref: '#/definitions/store.ManagedSessionArchive'
$ref: '#/definitions/sessions.ManagedArchive'
"400":
description: Bad Request
schema:
Expand Down
2 changes: 1 addition & 1 deletion services/core/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Two errors are shared across domains, each with one `api` helper: `textvalue.Err

Shared vocabulary has one owner each, and domains use it rather than copy it. `internal/environmentconfig` owns Environment setup, Skills, Plugins and initial files with their validation and public metadata; `Setup.Validate` checks requested configuration, where a Skill may be an unresolved reference, and `Setup.ValidateInstalled` checks frozen, installable configuration. `internal/skills` owns `ParseVersion`, the canonical positive decimal Skill version. `internal/metadata` owns the metadata rules: `Validate` for the pair, key and value limits and U+0000, `ValidateStorable` for U+0000 alone, and `Encode` with its 64 KiB bound. `internal/jsonobject` owns `Normalize`, the stable encoding of stored JSON objects that snapshots and retry identities compare. These packages import no persistence.

`internal/sessions` owns the Session change vocabulary and its decisions: the public changes that report Turn and Session transitions, what a Turn that ends settles, measured Turn usage and the Session activity a change reports. `internal/items` owns public Items: it projects observations, merges them into stored Items and builds the ordered events that report each Item change. Neither imports persistence. `internal/persistence/postgres/sessionpg` loads the facts those decisions read and applies them inside the caller's Session transaction, under the Session lock: it allocates event sequence positions, event IDs, Item positions and output indexes, writes the journal, Items, Turn usage and Artifact settlement, and prunes the journal. It decides nothing.
`internal/sessions` owns the Session vocabulary: Sessions, Turns, inputs, Environments and their provisioning failures, function calls, Item and Artifact reads, executor credentials, and the errors Session operations return, which `api` maps in `writeSessionsError`. It also owns the Session change vocabulary and its decisions: the public changes that report Turn and Session transitions, what a Turn that ends settles, measured Turn usage and the Session activity a change reports. `internal/items` owns public Items: it projects observations, merges them into stored Items and builds the ordered events that report each Item change. Neither imports persistence. `internal/persistence/postgres/sessionpg` loads the facts those decisions read and applies them inside the caller's Session transaction, under the Session lock: it allocates event sequence positions, event IDs, Item positions and output indexes, writes the journal, Items, Turn usage and Artifact settlement, and prunes the journal. It decides nothing.

`store` is transitional. `store.New` builds a pooled Store, and `store.NewExecution(s, lease)` builds the execution writer on a lease it borrows. An execution-only operation on a pooled Store fails with `store.ErrExecutionAuthority`. New adapters do not copy that check: their execution repositories require a `*pgunit.Lease` at construction, their public repositories expose no execution operation, and the check goes away with `store`.

Expand Down
11 changes: 6 additions & 5 deletions services/core/cmd/environment-key/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"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/identity"
"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sessions"
"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
Expand Down Expand Up @@ -111,7 +112,7 @@ func run() error {
if options.revoke {
return credentialOperationError(s.RevokeExecutorCredential(ctx, options.principal, options.keyID))
}
var credential store.IssuedExecutorCredential
var credential sessions.IssuedExecutorCredential
if options.rotate {
credential, err = s.RotateExecutorCredential(ctx, options.principal, options.keyID)
} else {
Expand All @@ -131,11 +132,11 @@ func credentialOperationError(err error) error {
switch {
case err == nil:
return nil
case errors.Is(err, store.ErrExecutorCredentialExists):
return store.ErrExecutorCredentialExists
case errors.Is(err, store.ErrNotFound):
case errors.Is(err, sessions.ErrExecutorCredentialExists):
return sessions.ErrExecutorCredentialExists
case errors.Is(err, sessions.ErrNotFound):
return errors.New("executor principal project mapping or authorized credential target not found")
case errors.Is(err, store.ErrInvalidInput):
case errors.Is(err, sessions.ErrInvalidInput):
return errors.New("invalid executor credential identity or target")
default:
return errors.New("executor credential database operation failed")
Expand Down
10 changes: 5 additions & 5 deletions services/core/cmd/environment-key/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strings"
"testing"

"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store"
"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sessions"
)

const (
Expand Down Expand Up @@ -141,9 +141,9 @@ func TestCredentialOperationErrorsDoNotExposeDatabaseValues(t *testing.T) {
const secret = "postgres://operator:private-password@database/execution"
for _, err := range []error{
errors.New(secret),
fmt.Errorf("%w: %s", store.ErrInvalidInput, secret),
fmt.Errorf("%w: %s", store.ErrNotFound, secret),
fmt.Errorf("%w: %s", store.ErrExecutorCredentialExists, secret),
fmt.Errorf("%w: %s", sessions.ErrInvalidInput, secret),
fmt.Errorf("%w: %s", sessions.ErrNotFound, secret),
fmt.Errorf("%w: %s", sessions.ErrExecutorCredentialExists, secret),
} {
redacted := credentialOperationError(err)
if redacted == nil || strings.Contains(redacted.Error(), secret) {
Expand All @@ -153,7 +153,7 @@ func TestCredentialOperationErrorsDoNotExposeDatabaseValues(t *testing.T) {
if err := credentialOperationError(nil); err != nil {
t.Fatalf("successful revocation returned an error: %v", err)
}
if !errors.Is(credentialOperationError(store.ErrExecutorCredentialExists), store.ErrExecutorCredentialExists) {
if !errors.Is(credentialOperationError(sessions.ErrExecutorCredentialExists), sessions.ErrExecutorCredentialExists) {
t.Fatal("duplicate key guidance was lost")
}
}
21 changes: 16 additions & 5 deletions services/core/cmd/server/http_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,25 @@ func daemonComposition(t testing.TB) http.Handler {
Vaults: struct{ api.Vaults }{}, VaultsReader: struct{ api.VaultsReader }{},
Files: struct{ api.Files }{}, FilesReader: struct{ api.FilesReader }{},
Skills: struct{ api.Skills }{}, SkillsReader: struct{ api.SkillsReader }{},
Agents: struct{ api.Agents }{}, AgentsReader: struct{ api.AgentsReader }{}, Sessions: struct{ api.Sessions }{}, SessionEvents: struct{ api.SessionEvents }{},
Agents: struct{ api.Agents }{}, AgentsReader: struct{ api.AgentsReader }{},
EnvironmentTemplates: struct{ api.EnvironmentTemplates }{}, EnvironmentTemplatesReader: struct{ api.EnvironmentTemplatesReader }{},
SessionHistory: struct{ api.SessionHistory }{}, Subagents: struct{ api.Subagents }{}, Artifacts: struct{ api.Artifacts }{},
SessionAdmin: struct{ api.SessionAdmin }{}, Environments: struct{ api.Environments }{}, ExecutorConnections: struct{ api.ExecutorConnections }{},
Sessions: struct{ api.Sessions }{},
SessionCreation: struct{ api.SessionCreation }{},
SessionEvents: struct{ api.SessionEvents }{},
Turns: struct{ api.Turns }{},
Items: struct{ api.Items }{},
Subagents: struct{ api.Subagents }{},
Artifacts: struct{ api.Artifacts }{},
SessionAdmin: struct{ api.SessionAdmin }{}, Environments: struct{ api.Environments }{}, ExecutorConnections: struct{ api.ExecutorConnections }{},
Admin: struct{ api.Admin }{}, AdminAudit: struct{ api.AdminAudit }{}, WriteAudit: struct{ api.WriteAudit }{}, Metrics: struct{ api.Metrics }{},
RuntimeObservations: struct{ api.RuntimeObservations }{}, RuntimeHistory: struct{ api.RuntimeHistory }{},
Execution: &api.Execution{ExecutorURL: "wss://core.example/api/v1/agent-daemon/ws", Admission: struct{ api.Admission }{},
SessionArchive: struct{ api.SessionArchive }{}, Workspaces: struct{ api.EnvironmentWorkspaces }{}},
Execution: &api.Execution{
ExecutorURL: "wss://core.example/api/v1/agent-daemon/ws",
SessionAdmission: struct{ api.SessionAdmission }{},
InputAdmission: struct{ api.InputAdmission }{},
SessionArchive: struct{ api.SessionArchive }{},
Workspaces: struct{ api.EnvironmentWorkspaces }{},
},
Sandboxes: &api.Sandboxes{Deployment: struct{ api.Deployment }{}, NodeAllocations: struct{ api.NodeAllocations }{}, DeploymentChanges: struct{ api.DeploymentChanges }{},
DeploymentReset: struct{ api.DeploymentReset }{}, ConfigurationDiscovery: struct{ api.ConfigurationDiscovery }{}},
})
Expand Down
21 changes: 17 additions & 4 deletions services/core/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,14 +369,27 @@ func run() error {
EnvironmentTemplates: environmentTemplates, EnvironmentTemplatesReader: templateStore,
Files: fileService, FilesReader: fileStore,
Agents: agentService, AgentsReader: agentStore,
Sessions: executionStore, SessionEvents: executionStore, SessionHistory: executionStore,
Subagents: executionStore, Artifacts: executionStore, SessionAdmin: executionStore,
Environments: executionStore, ExecutorConnections: executorConnections{store: executionStore, registry: registry},
Sessions: executionStore,
SessionCreation: executionStore,
SessionEvents: executionStore,
Turns: executionStore,
Items: executionStore,
Subagents: executionStore,
Artifacts: executionStore,
SessionAdmin: executionStore,
Environments: executionStore, ExecutorConnections: executorConnections{store: executionStore, registry: registry},
Admin: executionStore, AdminAudit: auditStore, WriteAudit: auditStore, Metrics: metrics,
RuntimeObservations: observationService, RuntimeHistory: historyService,
}
if worker != nil {
deps.Execution = &api.Execution{ExecutorURL: executorURL, Admission: worker, SessionArchive: worker, Workspaces: worker, NativeInstaller: nativeInstaller}
deps.Execution = &api.Execution{
ExecutorURL: executorURL,
SessionAdmission: worker,
InputAdmission: worker,
SessionArchive: worker,
Workspaces: worker,
NativeInstaller: nativeInstaller,
}
}
if managedNodes != nil {
deps.Sandboxes = &api.Sandboxes{
Expand Down
3 changes: 2 additions & 1 deletion services/core/internal/api/admin_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"net/http"

"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sessions"
"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store"
"github.com/go-chi/chi/v5"
)
Expand All @@ -15,7 +16,7 @@ type adminTenantContextKey struct{}
// Admin reads the administrator's cross-Project views: the asset summary and
// the Sessions whose Runtime is observed.
type Admin interface {
ReadAdminSummary(context.Context, string, store.AdminSummaryFilter, func(store.Session, *string) error) (store.AdminAssetCounts, error)
ReadAdminSummary(context.Context, string, store.AdminSummaryFilter, func(sessions.Session, *string) error) (store.AdminAssetCounts, error)
ListAdminRuntimeTargets(context.Context, []string, string, int, bool) (store.AdminRuntimeTargetPage, error)
}

Expand Down
4 changes: 2 additions & 2 deletions services/core/internal/api/admin_resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,10 @@ type summaryFixture struct {
filter store.AdminSummaryFilter
}

func (s *summaryFixture) ReadAdminSummary(_ context.Context, tenant string, filter store.AdminSummaryFilter, visit func(store.Session, *string) error) (store.AdminAssetCounts, error) {
func (s *summaryFixture) ReadAdminSummary(_ context.Context, tenant string, filter store.AdminSummaryFilter, visit func(sessions.Session, *string) error) (store.AdminAssetCounts, error) {
s.tenant, s.filter = tenant, filter
for i, usage := range []json.RawMessage{nil, json.RawMessage(`{"input_tokens":3,"output_tokens":5,"total_tokens":8,"input_tokens_details":{"cached_tokens":2},"output_tokens_details":{"reasoning_tokens":1}}`)} {
session := store.Session{ID: "session", TenantID: tenant, Configuration: json.RawMessage(`{"agent":{"id":"agent","model":"model","tools":[]},"environment":{"type":"none"}}`), CreatedAt: time.Unix(100+int64(i), 0), Usage: usage}
session := sessions.Session{ID: "session", TenantID: tenant, Configuration: json.RawMessage(`{"agent":{"id":"agent","model":"model","tools":[]},"environment":{"type":"none"}}`), CreatedAt: time.Unix(100+int64(i), 0), Usage: usage}
if i == 0 {
session.LastTurn = &sessions.Turn{Status: sessions.TurnInProgress, CreatedAt: time.Unix(110, 0)}
}
Expand Down
12 changes: 6 additions & 6 deletions services/core/internal/api/admin_session_archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import (
"context"
"net/http"

"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/store"
"github.com/MiniMax-AI/OpenAgentCore/services/core/internal/sessions"
"github.com/go-chi/chi/v5"
)

// SessionArchive archives a managed Session through the execution owner;
// SessionAdmin reads its archive state.
type SessionArchive interface {
ArchiveManagedSession(context.Context, string, string, uint64) (store.ManagedSessionArchive, error)
ArchiveManagedSession(context.Context, string, string, uint64) (sessions.ManagedArchive, error)
}

type AdminSessionArchiveRequest struct {
Expand All @@ -27,7 +27,7 @@ type AdminSessionArchiveRequest struct {
// @Param project_id path string true "Project ID"
// @Param session_id path string true "Session ID"
// @Param body body api.AdminSessionArchiveRequest true "Current deployment generation"
// @Success 200 {object} store.ManagedSessionArchive
// @Success 200 {object} sessions.ManagedArchive
// @Failure 400,401,404,409,413,500,503 {object} CoreErrorResponse
// @Router /core/v1/projects/{project_id}/sessions/{session_id}/archive [post]
func (h *Handler) adminArchiveSession(w http.ResponseWriter, r *http.Request) {
Expand All @@ -37,11 +37,11 @@ func (h *Handler) adminArchiveSession(w http.ResponseWriter, r *http.Request) {
}
var input AdminSessionArchiveRequest
if decodeInputObject(raw, &input, "expected_generation") != nil || input.ExpectedGeneration == 0 {
writeStoreError(w, r, store.ErrInvalidInput)
writeStoreError(w, r, sessions.ErrInvalidInput)
return
}
if h.Execution == nil {
writeStoreError(w, r, store.ErrEnvironmentUnavailable)
writeStoreError(w, r, sessions.ErrEnvironmentUnavailable)
return
}
result, err := h.Execution.SessionArchive.ArchiveManagedSession(r.Context(), tenantID(r), chi.URLParam(r, "session_id"), input.ExpectedGeneration)
Expand All @@ -59,7 +59,7 @@ func (h *Handler) adminArchiveSession(w http.ResponseWriter, r *http.Request) {
// @Security DeploymentAdminAuth
// @Param project_id path string true "Project ID"
// @Param session_id path string true "Session ID"
// @Success 200 {object} store.ManagedSessionArchive
// @Success 200 {object} sessions.ManagedArchive
// @Failure 400,401,404,500,503 {object} CoreErrorResponse
// @Router /core/v1/projects/{project_id}/sessions/{session_id}/archive [get]
func (h *Handler) adminGetSessionArchive(w http.ResponseWriter, r *http.Request) {
Expand Down
Loading
Loading