Skip to content

Latest commit

 

History

History
119 lines (91 loc) · 5.8 KB

File metadata and controls

119 lines (91 loc) · 5.8 KB

LLM Agent Notes

Reference companion to AGENTS.md. Use this file when an LLM needs to answer "how do I do X with this library" quickly, without reading every source file.

Minimum Working Client

client, err := vsax.NewClient(vsax.Config{
    ServerName:  "vsax.example.com",
    TokenID:     os.Getenv("VSAX_TOKEN_ID"),
    TokenSecret: os.Getenv("VSAX_TOKEN_SECRET"),
})

Everything else hangs off client.<Service>.<Method>.

Pattern Recognition

  • List pages: every list endpoint exposes both List(ctx, *Query) (*PagedResult[T], error) and All(ctx, *Query) iter.Seq2[T, error]. Prefer All unless you need access to Meta.TotalCount or manual page control.
  • Single-item get: Get(ctx, id) — device IDs are string GUIDs; org/site/group IDs are int64.
  • Create: Create(ctx, *XRequest) (*X, error) — always pass a typed *XRequest body.
  • Run-style endpoints (workflows, tasks, scripts): Run(ctx, id, *RunXRequest); pass nil when no parameters are needed.
  • Sub-resource lists (e.g. Devices.Notifications): mirror the same List / AllFoo pair.

OData Query Cheat Sheet

vsax.NewQuery().Top(100)                        // $top=100
vsax.NewQuery().Skip(100)                       // $skip=100
vsax.NewQuery().Count(true)                     // $count=true
vsax.NewQuery().OrderBy("Name desc")            // $orderby=Name desc
vsax.NewQuery().Filter("GroupId eq 5")          // raw $filter
vsax.NewQuery().Filter(vsax.Field("Name").Contains("web"))
vsax.NewQuery().ScopeID(42)                     // scopeId=42 (devices only)
vsax.NewQuery().Include(vsax.IncludeSecurity)   // assets only
vsax.NewQuery().Set("deviceId", "guid")         // escape hatch for arbitrary params

Field(name) methods: Eq, Ne, Gt, Ge, Lt, Le, Contains, StartsWith, EndsWith. Compose with vsax.And(a, b), vsax.Or(a, b), vsax.Not(a).

Errors At A Glance

Sentinel Typical cause
vsax.ErrUnauthorized invalid/expired token (401)
vsax.ErrForbidden authenticated but lacks permissions (403)
vsax.ErrNotFound resource doesn't exist (404)
vsax.ErrBadRequest validation failure (400)
vsax.ErrServer 500/502/503/504
if errors.Is(err, vsax.ErrNotFound) { /* ... */ }

var ve *vsax.ValidationError
if errors.As(err, &ve) {
    log.Printf("bad request: %s", ve.Base.Message)
}

Under-Specified Endpoints

These return flexible JSON payloads that vary by tenant config:

Endpoint Wrapper Unwrap
/patchmanagement/policies/{id} PolicyDocument doc.As(&myPolicy)
/patchmanagement/globalrules PolicyDocument doc.As(&rules)
/endpointprotection/policies/{id} PolicyDocument doc.As(&policy)
/environment Environment (typed; License is json.RawMessage) env.DecodeLicense(&lic)
/groups/{id}/package/{type} GroupPackage (typed Name, Url) direct
/customfields/{id}/usage paged []CustomFieldUsageEntry direct
/scopes/{id}/usage paged []ScopeUsageEntry direct

PolicyDocument wraps raw JSON via Raw json.RawMessage. Round-trip safely — if you re-marshal the wrapper, you get the original JSON back.

Endpoint Path Quirks

The VSA X surface has a few path shapes worth knowing:

  • Automation lives under /automation/: /automation/workflows, /automation/tasks, /automation/scripts.
  • Workflow executions are addressed by execution ID alone (no workflow ID in the path): /automation/workflows/executions/{id}. Workflows.Executions() lists executions across all workflows — filter by WorkflowId to scope to one.
  • Workflow cancellation is a bulk POST: POST /automation/workflows/executions/cancel with { "ExecutionIds": [...] }. Use Workflows.CancelExecutions(ids...).
  • Task executions are addressed by execution ID only: /automation/tasks/executions/{id}. Sub-resources: /devices, /devices/{deviceId}/scripts, /devices/{deviceId}/scripts/{scriptId}.
  • Script executions live under a script + device + execution tuple: /automation/scripts/{scriptId}/device/{deviceId}/executions[/{executionId}].
  • Notification webhooks are under /notifications/webhooks (note the / — not a single /notificationwebhooks word).
  • Custom fields use camelCase in the path: /customFields, /customFields/{id}/assign, /customFields/{id}/updateAssigned, /customFields/{id}/unassign.
  • Audit logs are under /auditlogs (plural).

Device Tab UI (Publish)

DeviceService.Publish registers or updates a device and can populate the "details" view with tabs of labels and webhook commands:

client.Devices.Publish(ctx, &vsax.PublishDevice{
    InstanceID: "my-instance-123",
    GroupID:    42,
    Name:       "Widget",
    Contents: []vsax.PublishDeviceTab{{
        Name: "Status",
        Contents: []vsax.PublishDeviceEntry{
            {Type: "label", Title: "State", Subtitle: "Running", Icon: "information"},
            {Type: "webhook_command", Title: "Restart", CallbackURL: "https://my.app/restart"},
        },
    }},
    NextRefreshIntervalMinutes: 15,
})

Valid Type values: "label", "webhook_command". Valid Icon: "information", "warning", "error".

Testing Patterns

The test suite uses httptest.NewServer and disables retries (MaxRetries: &zero) so tests run fast. When adding tests for new endpoints, mirror that pattern.

Known Upstream Gaps (2026-04-20)

  • The VSA X docs HTML is the only spec. No OpenAPI/Swagger.
  • Rate-limit behaviour is undocumented — client does exponential backoff for 5xx, but no token-bucket throttling.
  • Patch-management and endpoint-protection response shapes are tenant/OS dependent. Prefer As(dst) with a struct you've verified against real responses; fall back to Raw when structure is unknown.