From a8a63818c771cf246cb068c1512f68d8bbd311e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Mon, 30 Mar 2026 12:32:02 +0200 Subject: [PATCH] feat(api): add duration_ms to audit log entries (#758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(api): add duration_ms to audit log entries Server-computed duration in milliseconds (started_at → ended_at) on the list audit logs endpoint. Null when ended_at is not set. Closes #749 * feat(api): add duration_ms to audit log entries and type audit endpoints - Add server-computed duration_ms (started_at → ended_at) to audit log list response. Null when ended_at is not set. - Add typed Pydantic response models for both audit log endpoints (list and stats) so they appear in the OpenAPI spec. - Regenerate OpenAPI spec and all client SDKs. Closes #749 * chore: regenerate docs skill after audit log response models --- hindsight-api-slim/hindsight_api/api/http.py | 49 ++ hindsight-clients/go/api/openapi.yaml | 185 +++++++- hindsight-clients/go/api_audit.go | 16 +- hindsight-clients/go/model_audit_log_entry.go | 442 ++++++++++++++++++ .../go/model_audit_log_list_response.go | 270 +++++++++++ .../go/model_audit_log_stats_bucket.go | 214 +++++++++ .../go/model_audit_log_stats_response.go | 270 +++++++++++ .../python/.openapi-generator/FILES | 4 + .../python/hindsight_client_api/__init__.py | 4 + .../hindsight_client_api/api/audit_api.py | 24 +- .../hindsight_client_api/models/__init__.py | 4 + .../models/audit_log_entry.py | 135 ++++++ .../models/audit_log_list_response.py | 103 ++++ .../models/audit_log_stats_bucket.py | 91 ++++ .../models/audit_log_stats_response.py | 103 ++++ .../typescript/generated/types.gen.ts | 144 +++++- hindsight-docs/static/openapi.json | 213 ++++++++- .../changelog/integrations/codex.md | 19 + .../references/developer/configuration.md | 1 + skills/hindsight-docs/references/openapi.json | 213 ++++++++- .../references/sdks/integrations/codex.md | 29 +- 21 files changed, 2488 insertions(+), 45 deletions(-) create mode 100644 hindsight-clients/go/model_audit_log_entry.go create mode 100644 hindsight-clients/go/model_audit_log_list_response.go create mode 100644 hindsight-clients/go/model_audit_log_stats_bucket.go create mode 100644 hindsight-clients/go/model_audit_log_stats_response.go create mode 100644 hindsight-clients/python/hindsight_client_api/models/audit_log_entry.py create mode 100644 hindsight-clients/python/hindsight_client_api/models/audit_log_list_response.py create mode 100644 hindsight-clients/python/hindsight_client_api/models/audit_log_stats_bucket.py create mode 100644 hindsight-clients/python/hindsight_client_api/models/audit_log_stats_response.py create mode 100644 skills/hindsight-docs/references/changelog/integrations/codex.md diff --git a/hindsight-api-slim/hindsight_api/api/http.py b/hindsight-api-slim/hindsight_api/api/http.py index 064ebdb0..08896f35 100644 --- a/hindsight-api-slim/hindsight_api/api/http.py +++ b/hindsight-api-slim/hindsight_api/api/http.py @@ -5021,12 +5021,55 @@ def _register_routes(app: FastAPI): # ---- Audit Logs ---- + class AuditLogEntry(BaseModel): + """A single audit log entry.""" + + id: str + action: str + transport: str + bank_id: str | None + started_at: str | None + ended_at: str | None + duration_ms: int | None = Field( + default=None, + description="Server-computed duration in milliseconds (started_at → ended_at). Null if not yet completed.", + ) + request: dict[str, Any] | None + response: dict[str, Any] | None + metadata: dict[str, Any] + + class AuditLogListResponse(BaseModel): + """Response model for list audit logs endpoint.""" + + bank_id: str + total: int + limit: int + offset: int + items: list[AuditLogEntry] + + class AuditLogStatsBucket(BaseModel): + """A single time bucket in audit log stats.""" + + time: str + actions: dict[str, int] + total: int + + class AuditLogStatsResponse(BaseModel): + """Response model for audit log stats endpoint.""" + + bank_id: str + period: str + trunc: str + start: str + buckets: list[AuditLogStatsBucket] + @app.get( "/v1/default/banks/{bank_id}/audit-logs", summary="List audit logs", description="List audit log entries for a bank, ordered by most recent first.", operation_id="list_audit_logs", tags=["Audit"], + response_model=AuditLogListResponse, ) async def api_list_audit_logs( bank_id: str, @@ -5103,6 +5146,10 @@ def _register_routes(app: FastAPI): items = [] for row in rows: + duration_ms = None + if row["started_at"] and row["ended_at"]: + duration_ms = int((row["ended_at"] - row["started_at"]).total_seconds() * 1000) + items.append( { "id": str(row["id"]), @@ -5111,6 +5158,7 @@ def _register_routes(app: FastAPI): "bank_id": row["bank_id"], "started_at": row["started_at"].isoformat() if row["started_at"] else None, "ended_at": row["ended_at"].isoformat() if row["ended_at"] else None, + "duration_ms": duration_ms, "request": json.loads(row["request"]) if row["request"] else None, "response": json.loads(row["response"]) if row["response"] else None, "metadata": json.loads(row["metadata"]) if row["metadata"] else {}, @@ -5140,6 +5188,7 @@ def _register_routes(app: FastAPI): description="Get audit log counts grouped by time bucket for charting.", operation_id="audit_log_stats", tags=["Audit"], + response_model=AuditLogStatsResponse, ) async def api_audit_log_stats( bank_id: str, diff --git a/hindsight-clients/go/api/openapi.yaml b/hindsight-clients/go/api/openapi.yaml index 849a1c7f..2ffad873 100644 --- a/hindsight-clients/go/api/openapi.yaml +++ b/hindsight-clients/go/api/openapi.yaml @@ -2868,7 +2868,8 @@ paths: "200": content: application/json: - schema: {} + schema: + $ref: '#/components/schemas/AuditLogListResponse' description: Successful Response "422": content: @@ -2924,7 +2925,8 @@ paths: "200": content: application/json: - schema: {} + schema: + $ref: '#/components/schemas/AuditLogStatsResponse' description: Successful Response "422": content: @@ -2972,6 +2974,185 @@ components: - operation_id - status title: AsyncOperationSubmitResponse + AuditLogEntry: + description: A single audit log entry. + example: + duration_ms: 5 + request: + key: "" + metadata: + key: "" + bank_id: bank_id + response: + key: "" + action: action + started_at: started_at + id: id + transport: transport + ended_at: ended_at + properties: + id: + title: Id + type: string + action: + title: Action + type: string + transport: + title: Transport + type: string + bank_id: + nullable: true + type: string + started_at: + nullable: true + type: string + ended_at: + nullable: true + type: string + duration_ms: + nullable: true + type: integer + request: + additionalProperties: {} + nullable: true + response: + additionalProperties: {} + nullable: true + metadata: + additionalProperties: {} + title: Metadata + required: + - action + - bank_id + - ended_at + - id + - metadata + - request + - response + - started_at + - transport + title: AuditLogEntry + AuditLogListResponse: + description: Response model for list audit logs endpoint. + example: + total: 0 + offset: 1 + bank_id: bank_id + limit: 6 + items: + - duration_ms: 5 + request: + key: "" + metadata: + key: "" + bank_id: bank_id + response: + key: "" + action: action + started_at: started_at + id: id + transport: transport + ended_at: ended_at + - duration_ms: 5 + request: + key: "" + metadata: + key: "" + bank_id: bank_id + response: + key: "" + action: action + started_at: started_at + id: id + transport: transport + ended_at: ended_at + properties: + bank_id: + title: Bank Id + type: string + total: + title: Total + type: integer + limit: + title: Limit + type: integer + offset: + title: Offset + type: integer + items: + items: + $ref: '#/components/schemas/AuditLogEntry' + type: array + required: + - bank_id + - items + - limit + - offset + - total + title: AuditLogListResponse + AuditLogStatsBucket: + description: A single time bucket in audit log stats. + example: + total: 6 + time: time + actions: + key: 0 + properties: + time: + title: Time + type: string + actions: + additionalProperties: + type: integer + title: Actions + total: + title: Total + type: integer + required: + - actions + - time + - total + title: AuditLogStatsBucket + AuditLogStatsResponse: + description: Response model for audit log stats endpoint. + example: + period: period + trunc: trunc + bank_id: bank_id + buckets: + - total: 6 + time: time + actions: + key: 0 + - total: 6 + time: time + actions: + key: 0 + start: start + properties: + bank_id: + title: Bank Id + type: string + period: + title: Period + type: string + trunc: + title: Trunc + type: string + start: + title: Start + type: string + buckets: + items: + $ref: '#/components/schemas/AuditLogStatsBucket' + type: array + required: + - bank_id + - buckets + - period + - start + - trunc + title: AuditLogStatsResponse BackgroundResponse: description: "Response model for background update. Deprecated: use MissionResponse\ \ instead." diff --git a/hindsight-clients/go/api_audit.go b/hindsight-clients/go/api_audit.go index b5ee8fd2..582198d2 100644 --- a/hindsight-clients/go/api_audit.go +++ b/hindsight-clients/go/api_audit.go @@ -49,7 +49,7 @@ func (r ApiAuditLogStatsRequest) Authorization(authorization string) ApiAuditLog return r } -func (r ApiAuditLogStatsRequest) Execute() (interface{}, *http.Response, error) { +func (r ApiAuditLogStatsRequest) Execute() (*AuditLogStatsResponse, *http.Response, error) { return r.ApiService.AuditLogStatsExecute(r) } @@ -71,13 +71,13 @@ func (a *AuditAPIService) AuditLogStats(ctx context.Context, bankId string) ApiA } // Execute executes the request -// @return interface{} -func (a *AuditAPIService) AuditLogStatsExecute(r ApiAuditLogStatsRequest) (interface{}, *http.Response, error) { +// @return AuditLogStatsResponse +func (a *AuditAPIService) AuditLogStatsExecute(r ApiAuditLogStatsRequest) (*AuditLogStatsResponse, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue interface{} + localVarReturnValue *AuditLogStatsResponse ) localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "AuditAPIService.AuditLogStats") @@ -222,7 +222,7 @@ func (r ApiListAuditLogsRequest) Authorization(authorization string) ApiListAudi return r } -func (r ApiListAuditLogsRequest) Execute() (interface{}, *http.Response, error) { +func (r ApiListAuditLogsRequest) Execute() (*AuditLogListResponse, *http.Response, error) { return r.ApiService.ListAuditLogsExecute(r) } @@ -244,13 +244,13 @@ func (a *AuditAPIService) ListAuditLogs(ctx context.Context, bankId string) ApiL } // Execute executes the request -// @return interface{} -func (a *AuditAPIService) ListAuditLogsExecute(r ApiListAuditLogsRequest) (interface{}, *http.Response, error) { +// @return AuditLogListResponse +func (a *AuditAPIService) ListAuditLogsExecute(r ApiListAuditLogsRequest) (*AuditLogListResponse, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile - localVarReturnValue interface{} + localVarReturnValue *AuditLogListResponse ) localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "AuditAPIService.ListAuditLogs") diff --git a/hindsight-clients/go/model_audit_log_entry.go b/hindsight-clients/go/model_audit_log_entry.go new file mode 100644 index 00000000..498b5891 --- /dev/null +++ b/hindsight-clients/go/model_audit_log_entry.go @@ -0,0 +1,442 @@ +/* +Hindsight HTTP API + +HTTP API for Hindsight + +API version: 0.4.20 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package hindsight + +import ( + "encoding/json" + "bytes" + "fmt" +) + +// checks if the AuditLogEntry type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AuditLogEntry{} + +// AuditLogEntry A single audit log entry. +type AuditLogEntry struct { + Id string `json:"id"` + Action string `json:"action"` + Transport string `json:"transport"` + BankId NullableString `json:"bank_id"` + StartedAt NullableString `json:"started_at"` + EndedAt NullableString `json:"ended_at"` + DurationMs NullableInt32 `json:"duration_ms,omitempty"` + Request map[string]interface{} `json:"request"` + Response map[string]interface{} `json:"response"` + Metadata map[string]interface{} `json:"metadata"` +} + +type _AuditLogEntry AuditLogEntry + +// NewAuditLogEntry instantiates a new AuditLogEntry object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewAuditLogEntry(id string, action string, transport string, bankId NullableString, startedAt NullableString, endedAt NullableString, request map[string]interface{}, response map[string]interface{}, metadata map[string]interface{}) *AuditLogEntry { + this := AuditLogEntry{} + this.Id = id + this.Action = action + this.Transport = transport + this.BankId = bankId + this.StartedAt = startedAt + this.EndedAt = endedAt + this.Request = request + this.Response = response + this.Metadata = metadata + return &this +} + +// NewAuditLogEntryWithDefaults instantiates a new AuditLogEntry object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewAuditLogEntryWithDefaults() *AuditLogEntry { + this := AuditLogEntry{} + return &this +} + +// GetId returns the Id field value +func (o *AuditLogEntry) GetId() string { + if o == nil { + var ret string + return ret + } + + return o.Id +} + +// GetIdOk returns a tuple with the Id field value +// and a boolean to check if the value has been set. +func (o *AuditLogEntry) GetIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Id, true +} + +// SetId sets field value +func (o *AuditLogEntry) SetId(v string) { + o.Id = v +} + +// GetAction returns the Action field value +func (o *AuditLogEntry) GetAction() string { + if o == nil { + var ret string + return ret + } + + return o.Action +} + +// GetActionOk returns a tuple with the Action field value +// and a boolean to check if the value has been set. +func (o *AuditLogEntry) GetActionOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Action, true +} + +// SetAction sets field value +func (o *AuditLogEntry) SetAction(v string) { + o.Action = v +} + +// GetTransport returns the Transport field value +func (o *AuditLogEntry) GetTransport() string { + if o == nil { + var ret string + return ret + } + + return o.Transport +} + +// GetTransportOk returns a tuple with the Transport field value +// and a boolean to check if the value has been set. +func (o *AuditLogEntry) GetTransportOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Transport, true +} + +// SetTransport sets field value +func (o *AuditLogEntry) SetTransport(v string) { + o.Transport = v +} + +// GetBankId returns the BankId field value +// If the value is explicit nil, the zero value for string will be returned +func (o *AuditLogEntry) GetBankId() string { + if o == nil || o.BankId.Get() == nil { + var ret string + return ret + } + + return *o.BankId.Get() +} + +// GetBankIdOk returns a tuple with the BankId field value +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetBankIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.BankId.Get(), o.BankId.IsSet() +} + +// SetBankId sets field value +func (o *AuditLogEntry) SetBankId(v string) { + o.BankId.Set(&v) +} + +// GetStartedAt returns the StartedAt field value +// If the value is explicit nil, the zero value for string will be returned +func (o *AuditLogEntry) GetStartedAt() string { + if o == nil || o.StartedAt.Get() == nil { + var ret string + return ret + } + + return *o.StartedAt.Get() +} + +// GetStartedAtOk returns a tuple with the StartedAt field value +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetStartedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.StartedAt.Get(), o.StartedAt.IsSet() +} + +// SetStartedAt sets field value +func (o *AuditLogEntry) SetStartedAt(v string) { + o.StartedAt.Set(&v) +} + +// GetEndedAt returns the EndedAt field value +// If the value is explicit nil, the zero value for string will be returned +func (o *AuditLogEntry) GetEndedAt() string { + if o == nil || o.EndedAt.Get() == nil { + var ret string + return ret + } + + return *o.EndedAt.Get() +} + +// GetEndedAtOk returns a tuple with the EndedAt field value +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetEndedAtOk() (*string, bool) { + if o == nil { + return nil, false + } + return o.EndedAt.Get(), o.EndedAt.IsSet() +} + +// SetEndedAt sets field value +func (o *AuditLogEntry) SetEndedAt(v string) { + o.EndedAt.Set(&v) +} + +// GetDurationMs returns the DurationMs field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *AuditLogEntry) GetDurationMs() int32 { + if o == nil || IsNil(o.DurationMs.Get()) { + var ret int32 + return ret + } + return *o.DurationMs.Get() +} + +// GetDurationMsOk returns a tuple with the DurationMs field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetDurationMsOk() (*int32, bool) { + if o == nil { + return nil, false + } + return o.DurationMs.Get(), o.DurationMs.IsSet() +} + +// HasDurationMs returns a boolean if a field has been set. +func (o *AuditLogEntry) HasDurationMs() bool { + if o != nil && o.DurationMs.IsSet() { + return true + } + + return false +} + +// SetDurationMs gets a reference to the given NullableInt32 and assigns it to the DurationMs field. +func (o *AuditLogEntry) SetDurationMs(v int32) { + o.DurationMs.Set(&v) +} +// SetDurationMsNil sets the value for DurationMs to be an explicit nil +func (o *AuditLogEntry) SetDurationMsNil() { + o.DurationMs.Set(nil) +} + +// UnsetDurationMs ensures that no value is present for DurationMs, not even an explicit nil +func (o *AuditLogEntry) UnsetDurationMs() { + o.DurationMs.Unset() +} + +// GetRequest returns the Request field value +// If the value is explicit nil, the zero value for map[string]interface{} will be returned +func (o *AuditLogEntry) GetRequest() map[string]interface{} { + if o == nil { + var ret map[string]interface{} + return ret + } + + return o.Request +} + +// GetRequestOk returns a tuple with the Request field value +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetRequestOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.Request) { + return map[string]interface{}{}, false + } + return o.Request, true +} + +// SetRequest sets field value +func (o *AuditLogEntry) SetRequest(v map[string]interface{}) { + o.Request = v +} + +// GetResponse returns the Response field value +// If the value is explicit nil, the zero value for map[string]interface{} will be returned +func (o *AuditLogEntry) GetResponse() map[string]interface{} { + if o == nil { + var ret map[string]interface{} + return ret + } + + return o.Response +} + +// GetResponseOk returns a tuple with the Response field value +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AuditLogEntry) GetResponseOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.Response) { + return map[string]interface{}{}, false + } + return o.Response, true +} + +// SetResponse sets field value +func (o *AuditLogEntry) SetResponse(v map[string]interface{}) { + o.Response = v +} + +// GetMetadata returns the Metadata field value +func (o *AuditLogEntry) GetMetadata() map[string]interface{} { + if o == nil { + var ret map[string]interface{} + return ret + } + + return o.Metadata +} + +// GetMetadataOk returns a tuple with the Metadata field value +// and a boolean to check if the value has been set. +func (o *AuditLogEntry) GetMetadataOk() (map[string]interface{}, bool) { + if o == nil { + return map[string]interface{}{}, false + } + return o.Metadata, true +} + +// SetMetadata sets field value +func (o *AuditLogEntry) SetMetadata(v map[string]interface{}) { + o.Metadata = v +} + +func (o AuditLogEntry) MarshalJSON() ([]byte, error) { + toSerialize,err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AuditLogEntry) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["id"] = o.Id + toSerialize["action"] = o.Action + toSerialize["transport"] = o.Transport + toSerialize["bank_id"] = o.BankId.Get() + toSerialize["started_at"] = o.StartedAt.Get() + toSerialize["ended_at"] = o.EndedAt.Get() + if o.DurationMs.IsSet() { + toSerialize["duration_ms"] = o.DurationMs.Get() + } + if o.Request != nil { + toSerialize["request"] = o.Request + } + if o.Response != nil { + toSerialize["response"] = o.Response + } + toSerialize["metadata"] = o.Metadata + return toSerialize, nil +} + +func (o *AuditLogEntry) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "id", + "action", + "transport", + "bank_id", + "started_at", + "ended_at", + "request", + "response", + "metadata", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err; + } + + for _, requiredProperty := range(requiredProperties) { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varAuditLogEntry := _AuditLogEntry{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varAuditLogEntry) + + if err != nil { + return err + } + + *o = AuditLogEntry(varAuditLogEntry) + + return err +} + +type NullableAuditLogEntry struct { + value *AuditLogEntry + isSet bool +} + +func (v NullableAuditLogEntry) Get() *AuditLogEntry { + return v.value +} + +func (v *NullableAuditLogEntry) Set(val *AuditLogEntry) { + v.value = val + v.isSet = true +} + +func (v NullableAuditLogEntry) IsSet() bool { + return v.isSet +} + +func (v *NullableAuditLogEntry) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableAuditLogEntry(val *AuditLogEntry) *NullableAuditLogEntry { + return &NullableAuditLogEntry{value: val, isSet: true} +} + +func (v NullableAuditLogEntry) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableAuditLogEntry) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} + + diff --git a/hindsight-clients/go/model_audit_log_list_response.go b/hindsight-clients/go/model_audit_log_list_response.go new file mode 100644 index 00000000..f8cdca26 --- /dev/null +++ b/hindsight-clients/go/model_audit_log_list_response.go @@ -0,0 +1,270 @@ +/* +Hindsight HTTP API + +HTTP API for Hindsight + +API version: 0.4.20 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package hindsight + +import ( + "encoding/json" + "bytes" + "fmt" +) + +// checks if the AuditLogListResponse type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AuditLogListResponse{} + +// AuditLogListResponse Response model for list audit logs endpoint. +type AuditLogListResponse struct { + BankId string `json:"bank_id"` + Total int32 `json:"total"` + Limit int32 `json:"limit"` + Offset int32 `json:"offset"` + Items []AuditLogEntry `json:"items"` +} + +type _AuditLogListResponse AuditLogListResponse + +// NewAuditLogListResponse instantiates a new AuditLogListResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewAuditLogListResponse(bankId string, total int32, limit int32, offset int32, items []AuditLogEntry) *AuditLogListResponse { + this := AuditLogListResponse{} + this.BankId = bankId + this.Total = total + this.Limit = limit + this.Offset = offset + this.Items = items + return &this +} + +// NewAuditLogListResponseWithDefaults instantiates a new AuditLogListResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewAuditLogListResponseWithDefaults() *AuditLogListResponse { + this := AuditLogListResponse{} + return &this +} + +// GetBankId returns the BankId field value +func (o *AuditLogListResponse) GetBankId() string { + if o == nil { + var ret string + return ret + } + + return o.BankId +} + +// GetBankIdOk returns a tuple with the BankId field value +// and a boolean to check if the value has been set. +func (o *AuditLogListResponse) GetBankIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.BankId, true +} + +// SetBankId sets field value +func (o *AuditLogListResponse) SetBankId(v string) { + o.BankId = v +} + +// GetTotal returns the Total field value +func (o *AuditLogListResponse) GetTotal() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Total +} + +// GetTotalOk returns a tuple with the Total field value +// and a boolean to check if the value has been set. +func (o *AuditLogListResponse) GetTotalOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Total, true +} + +// SetTotal sets field value +func (o *AuditLogListResponse) SetTotal(v int32) { + o.Total = v +} + +// GetLimit returns the Limit field value +func (o *AuditLogListResponse) GetLimit() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Limit +} + +// GetLimitOk returns a tuple with the Limit field value +// and a boolean to check if the value has been set. +func (o *AuditLogListResponse) GetLimitOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Limit, true +} + +// SetLimit sets field value +func (o *AuditLogListResponse) SetLimit(v int32) { + o.Limit = v +} + +// GetOffset returns the Offset field value +func (o *AuditLogListResponse) GetOffset() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Offset +} + +// GetOffsetOk returns a tuple with the Offset field value +// and a boolean to check if the value has been set. +func (o *AuditLogListResponse) GetOffsetOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Offset, true +} + +// SetOffset sets field value +func (o *AuditLogListResponse) SetOffset(v int32) { + o.Offset = v +} + +// GetItems returns the Items field value +func (o *AuditLogListResponse) GetItems() []AuditLogEntry { + if o == nil { + var ret []AuditLogEntry + return ret + } + + return o.Items +} + +// GetItemsOk returns a tuple with the Items field value +// and a boolean to check if the value has been set. +func (o *AuditLogListResponse) GetItemsOk() ([]AuditLogEntry, bool) { + if o == nil { + return nil, false + } + return o.Items, true +} + +// SetItems sets field value +func (o *AuditLogListResponse) SetItems(v []AuditLogEntry) { + o.Items = v +} + +func (o AuditLogListResponse) MarshalJSON() ([]byte, error) { + toSerialize,err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AuditLogListResponse) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["bank_id"] = o.BankId + toSerialize["total"] = o.Total + toSerialize["limit"] = o.Limit + toSerialize["offset"] = o.Offset + toSerialize["items"] = o.Items + return toSerialize, nil +} + +func (o *AuditLogListResponse) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "bank_id", + "total", + "limit", + "offset", + "items", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err; + } + + for _, requiredProperty := range(requiredProperties) { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varAuditLogListResponse := _AuditLogListResponse{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varAuditLogListResponse) + + if err != nil { + return err + } + + *o = AuditLogListResponse(varAuditLogListResponse) + + return err +} + +type NullableAuditLogListResponse struct { + value *AuditLogListResponse + isSet bool +} + +func (v NullableAuditLogListResponse) Get() *AuditLogListResponse { + return v.value +} + +func (v *NullableAuditLogListResponse) Set(val *AuditLogListResponse) { + v.value = val + v.isSet = true +} + +func (v NullableAuditLogListResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableAuditLogListResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableAuditLogListResponse(val *AuditLogListResponse) *NullableAuditLogListResponse { + return &NullableAuditLogListResponse{value: val, isSet: true} +} + +func (v NullableAuditLogListResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableAuditLogListResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} + + diff --git a/hindsight-clients/go/model_audit_log_stats_bucket.go b/hindsight-clients/go/model_audit_log_stats_bucket.go new file mode 100644 index 00000000..40c99601 --- /dev/null +++ b/hindsight-clients/go/model_audit_log_stats_bucket.go @@ -0,0 +1,214 @@ +/* +Hindsight HTTP API + +HTTP API for Hindsight + +API version: 0.4.20 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package hindsight + +import ( + "encoding/json" + "bytes" + "fmt" +) + +// checks if the AuditLogStatsBucket type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AuditLogStatsBucket{} + +// AuditLogStatsBucket A single time bucket in audit log stats. +type AuditLogStatsBucket struct { + Time string `json:"time"` + Actions map[string]int32 `json:"actions"` + Total int32 `json:"total"` +} + +type _AuditLogStatsBucket AuditLogStatsBucket + +// NewAuditLogStatsBucket instantiates a new AuditLogStatsBucket object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewAuditLogStatsBucket(time string, actions map[string]int32, total int32) *AuditLogStatsBucket { + this := AuditLogStatsBucket{} + this.Time = time + this.Actions = actions + this.Total = total + return &this +} + +// NewAuditLogStatsBucketWithDefaults instantiates a new AuditLogStatsBucket object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewAuditLogStatsBucketWithDefaults() *AuditLogStatsBucket { + this := AuditLogStatsBucket{} + return &this +} + +// GetTime returns the Time field value +func (o *AuditLogStatsBucket) GetTime() string { + if o == nil { + var ret string + return ret + } + + return o.Time +} + +// GetTimeOk returns a tuple with the Time field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsBucket) GetTimeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Time, true +} + +// SetTime sets field value +func (o *AuditLogStatsBucket) SetTime(v string) { + o.Time = v +} + +// GetActions returns the Actions field value +func (o *AuditLogStatsBucket) GetActions() map[string]int32 { + if o == nil { + var ret map[string]int32 + return ret + } + + return o.Actions +} + +// GetActionsOk returns a tuple with the Actions field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsBucket) GetActionsOk() (map[string]int32, bool) { + if o == nil { + return map[string]int32{}, false + } + return o.Actions, true +} + +// SetActions sets field value +func (o *AuditLogStatsBucket) SetActions(v map[string]int32) { + o.Actions = v +} + +// GetTotal returns the Total field value +func (o *AuditLogStatsBucket) GetTotal() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Total +} + +// GetTotalOk returns a tuple with the Total field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsBucket) GetTotalOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Total, true +} + +// SetTotal sets field value +func (o *AuditLogStatsBucket) SetTotal(v int32) { + o.Total = v +} + +func (o AuditLogStatsBucket) MarshalJSON() ([]byte, error) { + toSerialize,err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AuditLogStatsBucket) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["time"] = o.Time + toSerialize["actions"] = o.Actions + toSerialize["total"] = o.Total + return toSerialize, nil +} + +func (o *AuditLogStatsBucket) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "time", + "actions", + "total", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err; + } + + for _, requiredProperty := range(requiredProperties) { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varAuditLogStatsBucket := _AuditLogStatsBucket{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varAuditLogStatsBucket) + + if err != nil { + return err + } + + *o = AuditLogStatsBucket(varAuditLogStatsBucket) + + return err +} + +type NullableAuditLogStatsBucket struct { + value *AuditLogStatsBucket + isSet bool +} + +func (v NullableAuditLogStatsBucket) Get() *AuditLogStatsBucket { + return v.value +} + +func (v *NullableAuditLogStatsBucket) Set(val *AuditLogStatsBucket) { + v.value = val + v.isSet = true +} + +func (v NullableAuditLogStatsBucket) IsSet() bool { + return v.isSet +} + +func (v *NullableAuditLogStatsBucket) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableAuditLogStatsBucket(val *AuditLogStatsBucket) *NullableAuditLogStatsBucket { + return &NullableAuditLogStatsBucket{value: val, isSet: true} +} + +func (v NullableAuditLogStatsBucket) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableAuditLogStatsBucket) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} + + diff --git a/hindsight-clients/go/model_audit_log_stats_response.go b/hindsight-clients/go/model_audit_log_stats_response.go new file mode 100644 index 00000000..9a5d4ced --- /dev/null +++ b/hindsight-clients/go/model_audit_log_stats_response.go @@ -0,0 +1,270 @@ +/* +Hindsight HTTP API + +HTTP API for Hindsight + +API version: 0.4.20 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package hindsight + +import ( + "encoding/json" + "bytes" + "fmt" +) + +// checks if the AuditLogStatsResponse type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AuditLogStatsResponse{} + +// AuditLogStatsResponse Response model for audit log stats endpoint. +type AuditLogStatsResponse struct { + BankId string `json:"bank_id"` + Period string `json:"period"` + Trunc string `json:"trunc"` + Start string `json:"start"` + Buckets []AuditLogStatsBucket `json:"buckets"` +} + +type _AuditLogStatsResponse AuditLogStatsResponse + +// NewAuditLogStatsResponse instantiates a new AuditLogStatsResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewAuditLogStatsResponse(bankId string, period string, trunc string, start string, buckets []AuditLogStatsBucket) *AuditLogStatsResponse { + this := AuditLogStatsResponse{} + this.BankId = bankId + this.Period = period + this.Trunc = trunc + this.Start = start + this.Buckets = buckets + return &this +} + +// NewAuditLogStatsResponseWithDefaults instantiates a new AuditLogStatsResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewAuditLogStatsResponseWithDefaults() *AuditLogStatsResponse { + this := AuditLogStatsResponse{} + return &this +} + +// GetBankId returns the BankId field value +func (o *AuditLogStatsResponse) GetBankId() string { + if o == nil { + var ret string + return ret + } + + return o.BankId +} + +// GetBankIdOk returns a tuple with the BankId field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsResponse) GetBankIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.BankId, true +} + +// SetBankId sets field value +func (o *AuditLogStatsResponse) SetBankId(v string) { + o.BankId = v +} + +// GetPeriod returns the Period field value +func (o *AuditLogStatsResponse) GetPeriod() string { + if o == nil { + var ret string + return ret + } + + return o.Period +} + +// GetPeriodOk returns a tuple with the Period field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsResponse) GetPeriodOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Period, true +} + +// SetPeriod sets field value +func (o *AuditLogStatsResponse) SetPeriod(v string) { + o.Period = v +} + +// GetTrunc returns the Trunc field value +func (o *AuditLogStatsResponse) GetTrunc() string { + if o == nil { + var ret string + return ret + } + + return o.Trunc +} + +// GetTruncOk returns a tuple with the Trunc field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsResponse) GetTruncOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Trunc, true +} + +// SetTrunc sets field value +func (o *AuditLogStatsResponse) SetTrunc(v string) { + o.Trunc = v +} + +// GetStart returns the Start field value +func (o *AuditLogStatsResponse) GetStart() string { + if o == nil { + var ret string + return ret + } + + return o.Start +} + +// GetStartOk returns a tuple with the Start field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsResponse) GetStartOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Start, true +} + +// SetStart sets field value +func (o *AuditLogStatsResponse) SetStart(v string) { + o.Start = v +} + +// GetBuckets returns the Buckets field value +func (o *AuditLogStatsResponse) GetBuckets() []AuditLogStatsBucket { + if o == nil { + var ret []AuditLogStatsBucket + return ret + } + + return o.Buckets +} + +// GetBucketsOk returns a tuple with the Buckets field value +// and a boolean to check if the value has been set. +func (o *AuditLogStatsResponse) GetBucketsOk() ([]AuditLogStatsBucket, bool) { + if o == nil { + return nil, false + } + return o.Buckets, true +} + +// SetBuckets sets field value +func (o *AuditLogStatsResponse) SetBuckets(v []AuditLogStatsBucket) { + o.Buckets = v +} + +func (o AuditLogStatsResponse) MarshalJSON() ([]byte, error) { + toSerialize,err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AuditLogStatsResponse) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["bank_id"] = o.BankId + toSerialize["period"] = o.Period + toSerialize["trunc"] = o.Trunc + toSerialize["start"] = o.Start + toSerialize["buckets"] = o.Buckets + return toSerialize, nil +} + +func (o *AuditLogStatsResponse) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "bank_id", + "period", + "trunc", + "start", + "buckets", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err; + } + + for _, requiredProperty := range(requiredProperties) { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varAuditLogStatsResponse := _AuditLogStatsResponse{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varAuditLogStatsResponse) + + if err != nil { + return err + } + + *o = AuditLogStatsResponse(varAuditLogStatsResponse) + + return err +} + +type NullableAuditLogStatsResponse struct { + value *AuditLogStatsResponse + isSet bool +} + +func (v NullableAuditLogStatsResponse) Get() *AuditLogStatsResponse { + return v.value +} + +func (v *NullableAuditLogStatsResponse) Set(val *AuditLogStatsResponse) { + v.value = val + v.isSet = true +} + +func (v NullableAuditLogStatsResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableAuditLogStatsResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableAuditLogStatsResponse(val *AuditLogStatsResponse) *NullableAuditLogStatsResponse { + return &NullableAuditLogStatsResponse{value: val, isSet: true} +} + +func (v NullableAuditLogStatsResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableAuditLogStatsResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} + + diff --git a/hindsight-clients/python/.openapi-generator/FILES b/hindsight-clients/python/.openapi-generator/FILES index 9ddf3ad3..31470d11 100644 --- a/hindsight-clients/python/.openapi-generator/FILES +++ b/hindsight-clients/python/.openapi-generator/FILES @@ -18,6 +18,10 @@ hindsight_client_api/exceptions.py hindsight_client_api/models/__init__.py hindsight_client_api/models/add_background_request.py hindsight_client_api/models/async_operation_submit_response.py +hindsight_client_api/models/audit_log_entry.py +hindsight_client_api/models/audit_log_list_response.py +hindsight_client_api/models/audit_log_stats_bucket.py +hindsight_client_api/models/audit_log_stats_response.py hindsight_client_api/models/background_response.py hindsight_client_api/models/bank_config_response.py hindsight_client_api/models/bank_config_update.py diff --git a/hindsight-clients/python/hindsight_client_api/__init__.py b/hindsight-clients/python/hindsight_client_api/__init__.py index dc302b92..7f37d83b 100644 --- a/hindsight-clients/python/hindsight_client_api/__init__.py +++ b/hindsight-clients/python/hindsight_client_api/__init__.py @@ -43,6 +43,10 @@ from hindsight_client_api.exceptions import ApiException # import models into sdk package from hindsight_client_api.models.add_background_request import AddBackgroundRequest from hindsight_client_api.models.async_operation_submit_response import AsyncOperationSubmitResponse +from hindsight_client_api.models.audit_log_entry import AuditLogEntry +from hindsight_client_api.models.audit_log_list_response import AuditLogListResponse +from hindsight_client_api.models.audit_log_stats_bucket import AuditLogStatsBucket +from hindsight_client_api.models.audit_log_stats_response import AuditLogStatsResponse from hindsight_client_api.models.background_response import BackgroundResponse from hindsight_client_api.models.bank_config_response import BankConfigResponse from hindsight_client_api.models.bank_config_update import BankConfigUpdate diff --git a/hindsight-clients/python/hindsight_client_api/api/audit_api.py b/hindsight-clients/python/hindsight_client_api/api/audit_api.py index 07bcc9a5..44997e71 100644 --- a/hindsight-clients/python/hindsight_client_api/api/audit_api.py +++ b/hindsight-clients/python/hindsight_client_api/api/audit_api.py @@ -17,8 +17,10 @@ from typing import Any, Dict, List, Optional, Tuple, Union from typing_extensions import Annotated from pydantic import Field, StrictStr -from typing import Any, Optional +from typing import Optional from typing_extensions import Annotated +from hindsight_client_api.models.audit_log_list_response import AuditLogListResponse +from hindsight_client_api.models.audit_log_stats_response import AuditLogStatsResponse from hindsight_client_api.api_client import ApiClient, RequestSerialized from hindsight_client_api.api_response import ApiResponse @@ -57,7 +59,7 @@ class AuditApi: _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> object: + ) -> AuditLogStatsResponse: """Audit log statistics Get audit log counts grouped by time bucket for charting. @@ -104,7 +106,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogStatsResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( @@ -137,7 +139,7 @@ class AuditApi: _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[object]: + ) -> ApiResponse[AuditLogStatsResponse]: """Audit log statistics Get audit log counts grouped by time bucket for charting. @@ -184,7 +186,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogStatsResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( @@ -264,7 +266,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogStatsResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( @@ -373,7 +375,7 @@ class AuditApi: _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> object: + ) -> AuditLogListResponse: """List audit logs List audit log entries for a bank, ordered by most recent first. @@ -432,7 +434,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogListResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( @@ -469,7 +471,7 @@ class AuditApi: _content_type: Optional[StrictStr] = None, _headers: Optional[Dict[StrictStr, Any]] = None, _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, - ) -> ApiResponse[object]: + ) -> ApiResponse[AuditLogListResponse]: """List audit logs List audit log entries for a bank, ordered by most recent first. @@ -528,7 +530,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogListResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( @@ -624,7 +626,7 @@ class AuditApi: ) _response_types_map: Dict[str, Optional[str]] = { - '200': "object", + '200': "AuditLogListResponse", '422': "HTTPValidationError", } response_data = await self.api_client.call_api( diff --git a/hindsight-clients/python/hindsight_client_api/models/__init__.py b/hindsight-clients/python/hindsight_client_api/models/__init__.py index 34c15840..087c409c 100644 --- a/hindsight-clients/python/hindsight_client_api/models/__init__.py +++ b/hindsight-clients/python/hindsight_client_api/models/__init__.py @@ -16,6 +16,10 @@ # import models into model package from hindsight_client_api.models.add_background_request import AddBackgroundRequest from hindsight_client_api.models.async_operation_submit_response import AsyncOperationSubmitResponse +from hindsight_client_api.models.audit_log_entry import AuditLogEntry +from hindsight_client_api.models.audit_log_list_response import AuditLogListResponse +from hindsight_client_api.models.audit_log_stats_bucket import AuditLogStatsBucket +from hindsight_client_api.models.audit_log_stats_response import AuditLogStatsResponse from hindsight_client_api.models.background_response import BackgroundResponse from hindsight_client_api.models.bank_config_response import BankConfigResponse from hindsight_client_api.models.bank_config_update import BankConfigUpdate diff --git a/hindsight-clients/python/hindsight_client_api/models/audit_log_entry.py b/hindsight-clients/python/hindsight_client_api/models/audit_log_entry.py new file mode 100644 index 00000000..582410b2 --- /dev/null +++ b/hindsight-clients/python/hindsight_client_api/models/audit_log_entry.py @@ -0,0 +1,135 @@ +# coding: utf-8 + +""" + Hindsight HTTP API + + HTTP API for Hindsight + + The version of the OpenAPI document: 0.4.20 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self + +class AuditLogEntry(BaseModel): + """ + A single audit log entry. + """ # noqa: E501 + id: StrictStr + action: StrictStr + transport: StrictStr + bank_id: Optional[StrictStr] + started_at: Optional[StrictStr] + ended_at: Optional[StrictStr] + duration_ms: Optional[StrictInt] = None + request: Optional[Dict[str, Any]] + response: Optional[Dict[str, Any]] + metadata: Dict[str, Any] + __properties: ClassVar[List[str]] = ["id", "action", "transport", "bank_id", "started_at", "ended_at", "duration_ms", "request", "response", "metadata"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AuditLogEntry from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if bank_id (nullable) is None + # and model_fields_set contains the field + if self.bank_id is None and "bank_id" in self.model_fields_set: + _dict['bank_id'] = None + + # set to None if started_at (nullable) is None + # and model_fields_set contains the field + if self.started_at is None and "started_at" in self.model_fields_set: + _dict['started_at'] = None + + # set to None if ended_at (nullable) is None + # and model_fields_set contains the field + if self.ended_at is None and "ended_at" in self.model_fields_set: + _dict['ended_at'] = None + + # set to None if duration_ms (nullable) is None + # and model_fields_set contains the field + if self.duration_ms is None and "duration_ms" in self.model_fields_set: + _dict['duration_ms'] = None + + # set to None if request (nullable) is None + # and model_fields_set contains the field + if self.request is None and "request" in self.model_fields_set: + _dict['request'] = None + + # set to None if response (nullable) is None + # and model_fields_set contains the field + if self.response is None and "response" in self.model_fields_set: + _dict['response'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AuditLogEntry from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "id": obj.get("id"), + "action": obj.get("action"), + "transport": obj.get("transport"), + "bank_id": obj.get("bank_id"), + "started_at": obj.get("started_at"), + "ended_at": obj.get("ended_at"), + "duration_ms": obj.get("duration_ms"), + "request": obj.get("request"), + "response": obj.get("response"), + "metadata": obj.get("metadata") + }) + return _obj + + diff --git a/hindsight-clients/python/hindsight_client_api/models/audit_log_list_response.py b/hindsight-clients/python/hindsight_client_api/models/audit_log_list_response.py new file mode 100644 index 00000000..313ac5c8 --- /dev/null +++ b/hindsight-clients/python/hindsight_client_api/models/audit_log_list_response.py @@ -0,0 +1,103 @@ +# coding: utf-8 + +""" + Hindsight HTTP API + + HTTP API for Hindsight + + The version of the OpenAPI document: 0.4.20 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List +from hindsight_client_api.models.audit_log_entry import AuditLogEntry +from typing import Optional, Set +from typing_extensions import Self + +class AuditLogListResponse(BaseModel): + """ + Response model for list audit logs endpoint. + """ # noqa: E501 + bank_id: StrictStr + total: StrictInt + limit: StrictInt + offset: StrictInt + items: List[AuditLogEntry] + __properties: ClassVar[List[str]] = ["bank_id", "total", "limit", "offset", "items"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AuditLogListResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in items (list) + _items = [] + if self.items: + for _item_items in self.items: + if _item_items: + _items.append(_item_items.to_dict()) + _dict['items'] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AuditLogListResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "bank_id": obj.get("bank_id"), + "total": obj.get("total"), + "limit": obj.get("limit"), + "offset": obj.get("offset"), + "items": [AuditLogEntry.from_dict(_item) for _item in obj["items"]] if obj.get("items") is not None else None + }) + return _obj + + diff --git a/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_bucket.py b/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_bucket.py new file mode 100644 index 00000000..3ba15761 --- /dev/null +++ b/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_bucket.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +""" + Hindsight HTTP API + + HTTP API for Hindsight + + The version of the OpenAPI document: 0.4.20 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictInt, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class AuditLogStatsBucket(BaseModel): + """ + A single time bucket in audit log stats. + """ # noqa: E501 + time: StrictStr + actions: Dict[str, StrictInt] + total: StrictInt + __properties: ClassVar[List[str]] = ["time", "actions", "total"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AuditLogStatsBucket from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AuditLogStatsBucket from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "time": obj.get("time"), + "actions": obj.get("actions"), + "total": obj.get("total") + }) + return _obj + + diff --git a/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_response.py b/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_response.py new file mode 100644 index 00000000..55a410b5 --- /dev/null +++ b/hindsight-clients/python/hindsight_client_api/models/audit_log_stats_response.py @@ -0,0 +1,103 @@ +# coding: utf-8 + +""" + Hindsight HTTP API + + HTTP API for Hindsight + + The version of the OpenAPI document: 0.4.20 + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, StrictStr +from typing import Any, ClassVar, Dict, List +from hindsight_client_api.models.audit_log_stats_bucket import AuditLogStatsBucket +from typing import Optional, Set +from typing_extensions import Self + +class AuditLogStatsResponse(BaseModel): + """ + Response model for audit log stats endpoint. + """ # noqa: E501 + bank_id: StrictStr + period: StrictStr + trunc: StrictStr + start: StrictStr + buckets: List[AuditLogStatsBucket] + __properties: ClassVar[List[str]] = ["bank_id", "period", "trunc", "start", "buckets"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of AuditLogStatsResponse from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # override the default output from pydantic by calling `to_dict()` of each item in buckets (list) + _items = [] + if self.buckets: + for _item_buckets in self.buckets: + if _item_buckets: + _items.append(_item_buckets.to_dict()) + _dict['buckets'] = _items + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of AuditLogStatsResponse from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "bank_id": obj.get("bank_id"), + "period": obj.get("period"), + "trunc": obj.get("trunc"), + "start": obj.get("start"), + "buckets": [AuditLogStatsBucket.from_dict(_item) for _item in obj["buckets"]] if obj.get("buckets") is not None else None + }) + return _obj + + diff --git a/hindsight-clients/typescript/generated/types.gen.ts b/hindsight-clients/typescript/generated/types.gen.ts index d2412c70..0ccde400 100644 --- a/hindsight-clients/typescript/generated/types.gen.ts +++ b/hindsight-clients/typescript/generated/types.gen.ts @@ -40,6 +40,140 @@ export type AsyncOperationSubmitResponse = { status: string; }; +/** + * AuditLogEntry + * + * A single audit log entry. + */ +export type AuditLogEntry = { + /** + * Id + */ + id: string; + /** + * Action + */ + action: string; + /** + * Transport + */ + transport: string; + /** + * Bank Id + */ + bank_id: string | null; + /** + * Started At + */ + started_at: string | null; + /** + * Ended At + */ + ended_at: string | null; + /** + * Duration Ms + * + * Server-computed duration in milliseconds (started_at → ended_at). Null if not yet completed. + */ + duration_ms?: number | null; + /** + * Request + */ + request: { + [key: string]: unknown; + } | null; + /** + * Response + */ + response: { + [key: string]: unknown; + } | null; + /** + * Metadata + */ + metadata: { + [key: string]: unknown; + }; +}; + +/** + * AuditLogListResponse + * + * Response model for list audit logs endpoint. + */ +export type AuditLogListResponse = { + /** + * Bank Id + */ + bank_id: string; + /** + * Total + */ + total: number; + /** + * Limit + */ + limit: number; + /** + * Offset + */ + offset: number; + /** + * Items + */ + items: Array; +}; + +/** + * AuditLogStatsBucket + * + * A single time bucket in audit log stats. + */ +export type AuditLogStatsBucket = { + /** + * Time + */ + time: string; + /** + * Actions + */ + actions: { + [key: string]: number; + }; + /** + * Total + */ + total: number; +}; + +/** + * AuditLogStatsResponse + * + * Response model for audit log stats endpoint. + */ +export type AuditLogStatsResponse = { + /** + * Bank Id + */ + bank_id: string; + /** + * Period + */ + period: string; + /** + * Trunc + */ + trunc: string; + /** + * Start + */ + start: string; + /** + * Buckets + */ + buckets: Array; +}; + /** * BackgroundResponse * @@ -4937,9 +5071,12 @@ export type ListAuditLogsResponses = { /** * Successful Response */ - 200: unknown; + 200: AuditLogListResponse; }; +export type ListAuditLogsResponse = + ListAuditLogsResponses[keyof ListAuditLogsResponses]; + export type AuditLogStatsData = { body?: never; headers?: { @@ -4984,5 +5121,8 @@ export type AuditLogStatsResponses = { /** * Successful Response */ - 200: unknown; + 200: AuditLogStatsResponse; }; + +export type AuditLogStatsResponse2 = + AuditLogStatsResponses[keyof AuditLogStatsResponses]; diff --git a/hindsight-docs/static/openapi.json b/hindsight-docs/static/openapi.json index 070788f1..75b383bc 100644 --- a/hindsight-docs/static/openapi.json +++ b/hindsight-docs/static/openapi.json @@ -4215,7 +4215,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/AuditLogListResponse" + } } } }, @@ -4302,7 +4304,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/AuditLogStatsResponse" + } } } }, @@ -4370,6 +4374,211 @@ "status": "queued" } }, + "AuditLogEntry": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "action": { + "type": "string", + "title": "Action" + }, + "transport": { + "type": "string", + "title": "Transport" + }, + "bank_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Bank Id" + }, + "started_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Started At" + }, + "ended_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ended At" + }, + "duration_ms": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Duration Ms", + "description": "Server-computed duration in milliseconds (started_at \u2192 ended_at). Null if not yet completed." + }, + "request": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Request" + }, + "response": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Response" + }, + "metadata": { + "additionalProperties": true, + "type": "object", + "title": "Metadata" + } + }, + "type": "object", + "required": [ + "id", + "action", + "transport", + "bank_id", + "started_at", + "ended_at", + "request", + "response", + "metadata" + ], + "title": "AuditLogEntry", + "description": "A single audit log entry." + }, + "AuditLogListResponse": { + "properties": { + "bank_id": { + "type": "string", + "title": "Bank Id" + }, + "total": { + "type": "integer", + "title": "Total" + }, + "limit": { + "type": "integer", + "title": "Limit" + }, + "offset": { + "type": "integer", + "title": "Offset" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AuditLogEntry" + }, + "type": "array", + "title": "Items" + } + }, + "type": "object", + "required": [ + "bank_id", + "total", + "limit", + "offset", + "items" + ], + "title": "AuditLogListResponse", + "description": "Response model for list audit logs endpoint." + }, + "AuditLogStatsBucket": { + "properties": { + "time": { + "type": "string", + "title": "Time" + }, + "actions": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Actions" + }, + "total": { + "type": "integer", + "title": "Total" + } + }, + "type": "object", + "required": [ + "time", + "actions", + "total" + ], + "title": "AuditLogStatsBucket", + "description": "A single time bucket in audit log stats." + }, + "AuditLogStatsResponse": { + "properties": { + "bank_id": { + "type": "string", + "title": "Bank Id" + }, + "period": { + "type": "string", + "title": "Period" + }, + "trunc": { + "type": "string", + "title": "Trunc" + }, + "start": { + "type": "string", + "title": "Start" + }, + "buckets": { + "items": { + "$ref": "#/components/schemas/AuditLogStatsBucket" + }, + "type": "array", + "title": "Buckets" + } + }, + "type": "object", + "required": [ + "bank_id", + "period", + "trunc", + "start", + "buckets" + ], + "title": "AuditLogStatsResponse", + "description": "Response model for audit log stats endpoint." + }, "BackgroundResponse": { "properties": { "mission": { diff --git a/skills/hindsight-docs/references/changelog/integrations/codex.md b/skills/hindsight-docs/references/changelog/integrations/codex.md new file mode 100644 index 00000000..0748d7d4 --- /dev/null +++ b/skills/hindsight-docs/references/changelog/integrations/codex.md @@ -0,0 +1,19 @@ +--- +hide_table_of_contents: true +--- + +import PageHero from '@site/src/components/PageHero'; + + + +[← Codex CLI integration](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/codex) + +## [0.1.0](https://github.com/vectorize-io/hindsight/tree/integrations/codex/v0.1.0) + +**Features** + +- Added Hindsight memory integration for OpenAI Codex CLI with three hook scripts: SessionStart (daemon warm-up), UserPromptSubmit (auto-recall), and Stop (auto-retain). ([`0b17a67c`](https://github.com/vectorize-io/hindsight/commit/0b17a67c)) +- Full-session retain with session-level upsert using session ID as document ID. ([`0b17a67c`](https://github.com/vectorize-io/hindsight/commit/0b17a67c)) +- Dynamic bank IDs for per-project memory isolation. ([`0b17a67c`](https://github.com/vectorize-io/hindsight/commit/0b17a67c)) +- Automatic daemon lifecycle management with background pre-start. ([`0b17a67c`](https://github.com/vectorize-io/hindsight/commit/0b17a67c)) +- 57 automated tests covering content processing and end-to-end hook behavior. ([`71125cd9`](https://github.com/vectorize-io/hindsight/commit/71125cd9)) diff --git a/skills/hindsight-docs/references/developer/configuration.md b/skills/hindsight-docs/references/developer/configuration.md index 0f3c2e97..ee5f6f14 100644 --- a/skills/hindsight-docs/references/developer/configuration.md +++ b/skills/hindsight-docs/references/developer/configuration.md @@ -947,6 +947,7 @@ Configuration for MCP server endpoints. |----------|-------------|---------| | `HINDSIGHT_API_MCP_ENABLED` | Enable MCP server at `/mcp/{bank_id}/` | `true` | | `HINDSIGHT_API_MCP_ENABLED_TOOLS` | Comma-separated allowlist of MCP tools to expose globally (empty = all tools) | - | +| `HINDSIGHT_API_MCP_STATELESS` | Use stateless HTTP transport (POST-only). When `false`, enables stateful mode with GET/SSE support for server-initiated messages | `false` | | `HINDSIGHT_API_MCP_AUTH_TOKEN` | Bearer token for MCP authentication (optional) | - | | `HINDSIGHT_API_MCP_LOCAL_BANK_ID` | Memory bank ID for local MCP | `mcp` | | `HINDSIGHT_API_MCP_INSTRUCTIONS` | Additional instructions appended to retain/recall tool descriptions | - | diff --git a/skills/hindsight-docs/references/openapi.json b/skills/hindsight-docs/references/openapi.json index 070788f1..75b383bc 100644 --- a/skills/hindsight-docs/references/openapi.json +++ b/skills/hindsight-docs/references/openapi.json @@ -4215,7 +4215,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/AuditLogListResponse" + } } } }, @@ -4302,7 +4304,9 @@ "description": "Successful Response", "content": { "application/json": { - "schema": {} + "schema": { + "$ref": "#/components/schemas/AuditLogStatsResponse" + } } } }, @@ -4370,6 +4374,211 @@ "status": "queued" } }, + "AuditLogEntry": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "action": { + "type": "string", + "title": "Action" + }, + "transport": { + "type": "string", + "title": "Transport" + }, + "bank_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Bank Id" + }, + "started_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Started At" + }, + "ended_at": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ended At" + }, + "duration_ms": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Duration Ms", + "description": "Server-computed duration in milliseconds (started_at \u2192 ended_at). Null if not yet completed." + }, + "request": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Request" + }, + "response": { + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "title": "Response" + }, + "metadata": { + "additionalProperties": true, + "type": "object", + "title": "Metadata" + } + }, + "type": "object", + "required": [ + "id", + "action", + "transport", + "bank_id", + "started_at", + "ended_at", + "request", + "response", + "metadata" + ], + "title": "AuditLogEntry", + "description": "A single audit log entry." + }, + "AuditLogListResponse": { + "properties": { + "bank_id": { + "type": "string", + "title": "Bank Id" + }, + "total": { + "type": "integer", + "title": "Total" + }, + "limit": { + "type": "integer", + "title": "Limit" + }, + "offset": { + "type": "integer", + "title": "Offset" + }, + "items": { + "items": { + "$ref": "#/components/schemas/AuditLogEntry" + }, + "type": "array", + "title": "Items" + } + }, + "type": "object", + "required": [ + "bank_id", + "total", + "limit", + "offset", + "items" + ], + "title": "AuditLogListResponse", + "description": "Response model for list audit logs endpoint." + }, + "AuditLogStatsBucket": { + "properties": { + "time": { + "type": "string", + "title": "Time" + }, + "actions": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Actions" + }, + "total": { + "type": "integer", + "title": "Total" + } + }, + "type": "object", + "required": [ + "time", + "actions", + "total" + ], + "title": "AuditLogStatsBucket", + "description": "A single time bucket in audit log stats." + }, + "AuditLogStatsResponse": { + "properties": { + "bank_id": { + "type": "string", + "title": "Bank Id" + }, + "period": { + "type": "string", + "title": "Period" + }, + "trunc": { + "type": "string", + "title": "Trunc" + }, + "start": { + "type": "string", + "title": "Start" + }, + "buckets": { + "items": { + "$ref": "#/components/schemas/AuditLogStatsBucket" + }, + "type": "array", + "title": "Buckets" + } + }, + "type": "object", + "required": [ + "bank_id", + "period", + "trunc", + "start", + "buckets" + ], + "title": "AuditLogStatsResponse", + "description": "Response model for audit log stats endpoint." + }, "BackgroundResponse": { "properties": { "mission": { diff --git a/skills/hindsight-docs/references/sdks/integrations/codex.md b/skills/hindsight-docs/references/sdks/integrations/codex.md index edb3b697..ebc6a934 100644 --- a/skills/hindsight-docs/references/sdks/integrations/codex.md +++ b/skills/hindsight-docs/references/sdks/integrations/codex.md @@ -4,30 +4,23 @@ sidebar_position: 6 # OpenAI Codex CLI +[View Changelog →](../../changelog/integrations/codex.md) + Persistent memory for [OpenAI Codex CLI](https://github.com/openai/codex) using [Hindsight](https://vectorize.io/hindsight). Three Python hook scripts automatically recall relevant context before each prompt and retain conversations after each turn — no changes to your Codex workflow required. ## Quick Start ```bash -# 1. Clone the Hindsight repo and install the plugin -git clone https://github.com/vectorize-io/hindsight.git -cd hindsight/hindsight-integrations/codex -./install.sh - -# 2. Configure your Hindsight connection -cat > ~/.hindsight/codex.json << 'EOF' -{ - "hindsightApiUrl": "https://api.hindsight.vectorize.io", - "hindsightApiToken": "hsk_your_token_here", - "bankId": "codex" -} -EOF - -# 3. Start Codex — memory is live -codex +curl -fsSL https://hindsight.vectorize.io/get-codex | bash ``` -For a local Hindsight instance, set `hindsightApiUrl` to `http://localhost:9077` and omit `hindsightApiToken`. +The installer will guide you through choosing local or cloud mode and configuring your connection. Once installed, start a new Codex session — memory is live. + +To uninstall: + +```bash +curl -fsSL https://hindsight.vectorize.io/get-codex | bash -s -- --uninstall +``` ## Features @@ -172,7 +165,7 @@ With this config, running Codex in `~/projects/api` and `~/projects/frontend` st ## Troubleshooting -**Hooks not firing**: Check that `~/.codex/config.toml` contains `codex_hooks = true` under `[features]`. Re-run `install.sh` to write this automatically. +**Hooks not firing**: Check that `~/.codex/config.toml` contains `codex_hooks = true` under `[features]`. Re-run the installer to fix this automatically. **No memories recalled**: Recall returns results only after something has been retained. Either complete one Codex session first, or seed your bank manually using the [cookbook example](https://github.com/vectorize-io/hindsight-cookbook/tree/main/applications/codex-memory).