feat: establish v0.70 platform milestone
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-08-29 21:56:51 +08:00
parent d97bbf7cf5
commit e652516147
133 changed files with 12907 additions and 801 deletions
+61 -5
View File
@@ -14,9 +14,15 @@ export type SubjectFact = components["schemas"]["SubjectFact"];
export type Consent = components["schemas"]["Consent"];
export type ConversationReadiness = components["schemas"]["ConversationReadiness"];
export type ManagedDevice = components["schemas"]["ManagedDevice"];
export type OpsDevice = components["schemas"]["OpsDevice"];
export type OpsDeviceAssignmentOption = components["schemas"]["OpsDeviceAssignmentOption"];
export type DeviceCredentialIssue = components["schemas"]["DeviceCredentialIssue"];
export type DeviceClaimIssue = components["schemas"]["DeviceClaimIssue"];
export type DevicePresence = components["schemas"]["DevicePresence"];
export type DeviceTwin = components["schemas"]["DeviceTwin"];
export type DeviceCommand = components["schemas"]["DeviceCommand"];
export type DeviceBindingImpact = components["schemas"]["DeviceBindingImpact"];
export type DeviceBindingChangeResult = components["schemas"]["DeviceBindingChangeResult"];
export type FirmwareSigningKey = components["schemas"]["FirmwareSigningKey"];
export type FirmwareRelease = components["schemas"]["FirmwareRelease"];
export type FirmwareReleaseImpact = components["schemas"]["FirmwareReleaseImpact"];
@@ -33,6 +39,7 @@ export type MediaSegment = components["schemas"]["MediaSegment"];
export type RecordingAccessGrant = components["schemas"]["RecordingAccessGrant"];
export type MediaAccess = components["schemas"]["MediaAccess"];
export type Story = components["schemas"]["Story"];
export type FactCandidate = components["schemas"]["FactCandidate"];
export type CuratedMemory = components["schemas"]["CuratedMemory"];
export type PrivacyRequest = components["schemas"]["PrivacyRequest"];
export type ExportTask = components["schemas"]["ExportTask"];
@@ -43,9 +50,12 @@ export type OpsResourceReference = components["schemas"]["OpsResourceReference"]
export type OpsDeviceGroup = components["schemas"]["OpsDeviceGroup"];
export type OpsConfigRollout = components["schemas"]["OpsConfigRollout"];
export type OpsConfigTransitionRequest = components["schemas"]["OpsConfigTransitionRequest"];
export type ContentQualitySummary = components["schemas"]["ContentQualitySummary"];
export type ContentErrorType = components["schemas"]["ContentErrorType"];
export type BillingPriceBook = components["schemas"]["BillingPriceBook"];
export type QuotaPolicy = components["schemas"]["QuotaPolicy"];
export type CostSummary = components["schemas"]["CostSummary"];
export type UsageOverview = components["schemas"]["UsageOverview"];
export type AlertRoutingPolicy = components["schemas"]["AlertRoutingPolicy"];
export type AlertDeliveryTest = components["schemas"]["AlertDeliveryTest"];
export type AlertIncident = components["schemas"]["AlertIncident"];
@@ -115,6 +125,22 @@ export const platformApi = {
version: (signal?: AbortSignal) => getJSON<VersionResponse>("/api/v1/version", signal),
currentUser: (accessToken: string, signal?: AbortSignal) =>
getJSONWithToken<CurrentUserResponse>("/api/v1/me", accessToken, signal),
opsDevices: (tenantID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: OpsDevice[] }>>("GET", "/api/v1/ops/devices", accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
opsDeviceAssignmentOptions: (tenantID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: OpsDeviceAssignmentOption[] }>>("GET", "/api/v1/ops/device-assignment-options", accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
createOpsDevice: (tenantID: string, input: components["schemas"]["CreateOpsDeviceRequest"], accessToken: string) =>
authenticatedJSON<Envelope<{ device: OpsDevice; credential: DeviceCredentialIssue; claim?: DeviceClaimIssue }>>("POST", "/api/v1/ops/devices", accessToken, undefined, input, { "X-Tenant-Id": tenantID }),
updateOpsDevice: (tenantID: string, device: OpsDevice, input: components["schemas"]["UpdateOpsDeviceRequest"], accessToken: string) =>
authenticatedJSON<Envelope<OpsDevice>>("PATCH", `/api/v1/ops/devices/${device.id}`, accessToken, undefined, input, { "X-Tenant-Id": tenantID, "If-Match": `"v${device.version}"` }),
deleteOpsDevice: (tenantID: string, device: OpsDevice, accessToken: string) =>
authenticatedJSON<Envelope<OpsDevice>>("DELETE", `/api/v1/ops/devices/${device.id}`, accessToken, undefined, undefined, { "X-Tenant-Id": tenantID, "If-Match": `"v${device.version}"` }),
rotateOpsDeviceCredential: (tenantID: string, deviceID: string, accessToken: string) =>
authenticatedJSON<Envelope<DeviceCredentialIssue>>("POST", `/api/v1/ops/devices/${deviceID}/credentials/rotate`, accessToken, undefined, undefined, { "X-Tenant-Id": tenantID }),
issueOpsDeviceClaim: (tenantID: string, deviceID: string, accessToken: string) =>
authenticatedJSON<Envelope<DeviceClaimIssue>>("POST", `/api/v1/ops/devices/${deviceID}/claims`, accessToken, undefined, undefined, { "X-Tenant-Id": tenantID }),
opsContentQuality: (tenantID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: ContentQualitySummary[] }>>("GET", "/api/v1/ops/content-quality", accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
opsConfigVersions: (tenantID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: OpsConfigVersion[] }>>("GET", "/api/v1/ops/config-versions", accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
createOpsConfigVersion: (tenantID: string, input: components["schemas"]["CreateOpsConfigVersionRequest"], accessToken: string) =>
@@ -170,6 +196,8 @@ export const platformApi = {
{ "X-Tenant-Id": tenantID, "Idempotency-Key": `usage-quota-${crypto.randomUUID()}` }),
opsCostSummary: (tenantID: string, from: string, to: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<CostSummary>>("GET", `/api/v1/ops/cost-summary?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`, accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
opsUsageOverview: (tenantID: string, query: { from: string; to: string; timezone?: string; household_id?: string; device_id?: string }, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<UsageOverview>>("GET", `/api/v1/ops/usage-overview?${usageOverviewParameters(query)}`, accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
opsAlertRoutingPolicies: (tenantID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: AlertRoutingPolicy[] }>>("GET", "/api/v1/ops/alert-routing-policies", accessToken, signal, undefined, { "X-Tenant-Id": tenantID }),
createOpsAlertRoutingPolicy: (tenantID: string, input: components["schemas"]["CreateAlertRoutingPolicyRequest"], accessToken: string) =>
@@ -243,6 +271,9 @@ export const platformApi = {
authenticatedJSON<Envelope<{ items: Household[] }>>("GET", "/api/v1/households", accessToken, signal),
createHousehold: (tenantID: string, name: string, accessToken: string) =>
authenticatedJSON<Envelope<Household>>("POST", "/api/v1/households", accessToken, undefined, { name }, { "X-Tenant-Id": tenantID }),
updateHousehold: (household: Household, name: string, accessToken: string) =>
authenticatedJSON<Envelope<Household>>("PATCH", `/api/v1/households/${household.id}`, accessToken, undefined,
{ name }, { "If-Match": `"v${household.version}"` }),
subjects: (householdID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: Subject[] }>>("GET", `/api/v1/households/${householdID}/subjects`, accessToken, signal),
facts: (subjectID: string, accessToken: string, signal?: AbortSignal) =>
@@ -269,6 +300,8 @@ export const platformApi = {
authenticatedJSON<Envelope<ConversationDetail>>("GET", `/api/v1/conversations/${conversationID}`, accessToken, signal),
conversationUsage: (conversationID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<ConversationUsage>>("GET", `/api/v1/conversations/${conversationID}/usage`, accessToken, signal),
familyUsageOverview: (householdID: string, query: { from: string; to: string; timezone?: string; device_id?: string }, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<UsageOverview>>("GET", `/api/v1/households/${householdID}/usage-overview?${usageOverviewParameters(query)}`, accessToken, signal),
conversationTurns: (conversationID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: ConversationTurn[]; next_cursor?: string }>>("GET", `/api/v1/conversations/${conversationID}/turns?limit=100`, accessToken, signal),
conversationSummaries: (conversationID: string, accessToken: string, signal?: AbortSignal) =>
@@ -294,18 +327,21 @@ export const platformApi = {
authenticatedJSON<Envelope<{ items: Story[] }>>("GET", `/api/v1/subjects/${subjectID}/stories`, accessToken, signal),
story: (storyID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<Story>>("GET", `/api/v1/stories/${storyID}`, accessToken, signal),
reviseStory: (story: Story, content: string, reason: string, accessToken: string) =>
reviseStory: (story: Story, content: string, reason: string, accessToken: string, errorType?: ContentErrorType) =>
authenticatedJSON<Envelope<Story>>("PATCH", `/api/v1/stories/${story.id}`, accessToken, undefined,
{ content, reason }, { "If-Match": `"v${story.version}"` }),
{ content, reason, error_type: errorType }, { "If-Match": `"v${story.version}"` }),
updateFactCandidate: (storyID: string, fact: FactCandidate, input: components["schemas"]["UpdateFactCandidateRequest"], accessToken: string) =>
authenticatedJSON<Envelope<FactCandidate>>("PATCH", `/api/v1/stories/${storyID}/facts/${fact.id}`, accessToken, undefined,
input, { "If-Match": `"v${fact.version}"` }),
confirmStory: (story: Story, reason: string, accessToken: string) =>
authenticatedJSON<Envelope<{ story: Story; memory: CuratedMemory }>>("POST", `/api/v1/stories/${story.id}/confirm`, accessToken, undefined,
{ reason }, { "If-Match": `"v${story.version}"` }),
rejectStory: (story: Story, reason: string, accessToken: string) =>
rejectStory: (story: Story, reason: string, accessToken: string, errorType?: ContentErrorType) =>
authenticatedJSON<Envelope<Story>>("POST", `/api/v1/stories/${story.id}/reject`, accessToken, undefined,
{ reason }, { "If-Match": `"v${story.version}"` }),
{ reason, error_type: errorType }, { "If-Match": `"v${story.version}"` }),
memories: (subjectID: string, accessToken: string, signal?: AbortSignal) =>
authenticatedJSON<Envelope<{ items: CuratedMemory[] }>>("GET", `/api/v1/subjects/${subjectID}/memories`, accessToken, signal),
updateMemory: (memory: CuratedMemory, input: { content?: string; status?: "ACTIVE" | "DISABLED"; reason: string }, accessToken: string) =>
updateMemory: (memory: CuratedMemory, input: components["schemas"]["UpdateMemoryRequest"], accessToken: string) =>
authenticatedJSON<Envelope<CuratedMemory>>("PATCH", `/api/v1/memories/${memory.id}`, accessToken, undefined,
input, { "If-Match": `"v${memory.version}"` }),
deleteMemory: (memory: CuratedMemory, reason: string, accessToken: string) =>
@@ -318,6 +354,12 @@ export const platformApi = {
createPrivacyAccessRequest: (subjectID: string, categories: string[], accessToken: string) =>
authenticatedJSON<Envelope<PrivacyRequest>>("POST", `/api/v1/subjects/${subjectID}/privacy-requests`, accessToken, undefined,
{ request_type: "ACCESS", scope: { categories } }, { "Idempotency-Key": `privacy-access-${crypto.randomUUID()}` }),
createPrivacyCorrectionRequest: (subjectID: string, corrections: { preferred_name?: string; language?: string; timezone?: string; profile_data?: Record<string, unknown>; conversation_preferences?: Record<string, unknown> }, accessToken: string) =>
authenticatedJSON<Envelope<PrivacyRequest>>("POST", `/api/v1/subjects/${subjectID}/privacy-requests`, accessToken, undefined,
{ request_type: "CORRECTION", scope: { corrections } }, { "Idempotency-Key": `privacy-correction-${crypto.randomUUID()}` }),
createConsentWithdrawalRequest: (subjectID: string, consentTypes: components["schemas"]["ConsentType"][], accessToken: string) =>
authenticatedJSON<Envelope<PrivacyRequest>>("POST", `/api/v1/subjects/${subjectID}/privacy-requests`, accessToken, undefined,
{ request_type: "CONSENT_WITHDRAWAL", scope: { consent_types: consentTypes } }, { "Idempotency-Key": `privacy-consent-withdrawal-${crypto.randomUUID()}` }),
createPrivacyDeleteRequest: (subjectID: string, reason: string, confirmation: string, accessToken: string) =>
authenticatedJSON<Envelope<PrivacyRequest>>("POST", `/api/v1/subjects/${subjectID}/privacy-requests`, accessToken, undefined,
{ request_type: "DELETE", scope: {}, reason, confirmation }, { "Idempotency-Key": `privacy-delete-${crypto.randomUUID()}` }),
@@ -371,6 +413,13 @@ export const platformApi = {
authenticatedJSON<Envelope<Consent>>("POST", `/api/v1/subjects/${subjectID}/consents/${consentID}/withdraw`, accessToken),
claimDevice: (input: DeviceClaimRequest, accessToken: string) =>
authenticatedJSON<Envelope<components["schemas"]["DeviceClaimResult"]>>("POST", "/api/v1/device-claims", accessToken, undefined, input),
deviceBindingImpact: (deviceID: string, action: "unbind" | "transfer", targetSubjectID: string | undefined, accessToken: string, signal?: AbortSignal) => {
const query = new URLSearchParams({ action });
if (targetSubjectID) query.set("target_subject_id", targetSubjectID);
return authenticatedJSON<Envelope<DeviceBindingImpact>>("GET", `/api/v1/devices/${deviceID}/binding-impact?${query}`, accessToken, signal);
},
changeDeviceBinding: (deviceID: string, input: components["schemas"]["ChangeDeviceBindingRequest"], accessToken: string) =>
authenticatedJSON<Envelope<DeviceBindingChangeResult>>("POST", `/api/v1/devices/${deviceID}/binding-change`, accessToken, undefined, input),
updateDeviceTwin: (deviceID: string, revision: number, input: UpdateDeviceTwinRequest, accessToken: string) =>
authenticatedJSON<Envelope<DeviceTwin>>("PATCH", `/api/v1/devices/${deviceID}/twin`, accessToken, undefined, input,
{ "If-Match": `"v${revision}"` })
@@ -412,6 +461,13 @@ export const platformApi = {
{ rollback_release_id: rollbackReleaseID })
};
function usageOverviewParameters(query: { from: string; to: string; timezone?: string; household_id?: string; device_id?: string }) {
const parameters = new URLSearchParams({ from: query.from, to: query.to, timezone: query.timezone || "Asia/Shanghai" });
if (query.household_id) parameters.set("household_id", query.household_id);
if (query.device_id) parameters.set("device_id", query.device_id);
return parameters.toString();
}
async function getJSONWithToken<T>(path: string, accessToken: string, signal?: AbortSignal): Promise<T> {
return authenticatedJSON<T>("GET", path, accessToken, signal);
}
+1060 -5
View File
File diff suppressed because it is too large Load Diff