Record externally completed agent config imports (#34981)

## Why

Clients that complete an external agent config import outside the app server need a way to include the result in import history.

## What changed

- Add `externalAgentConfig/import/recordHistory` to persist completed item results and return a generated import ID.
- Store the optional provider ID for regular imports and expose it when reading import history.
- Update the generated JSON and TypeScript protocol schemas for the new request, response, and history field.

## Testing

- Cover recording and reading an externally completed import through the app-server protocol.
- Cover provider ID persistence and updates in the state runtime.

GitOrigin-RevId: 935401e899ec9eeb38f54c182e45a16642411deb
This commit is contained in:
charlesgong-openai authored and copyberry committed 2026-07-23 17:55:22 +00:00
1 parent 8d34c06672
commit ce803c45ae
22 files changed
+632 -22

No files matched your search

+142 -1
View File
@@ -911,6 +911,98 @@
}, },
"type": "object" "type": "object"
}, },
"ExternalAgentConfigImportHistoryRecordParams": {
"properties": {
"itemTypeResults": {
"description": "Completed results grouped by imported item type.",
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
},
"providerId": {
"description": "Opaque provider identifier for the externally completed import.",
"type": "string"
}
},
"required": [
"itemTypeResults",
"providerId"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"message": {
"type": "string"
},
"source": {
"type": [
"string",
"null"
]
},
"subErrorType": {
"type": [
"string",
"null"
]
}
},
"required": [
"failureStage",
"itemType",
"message"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeSuccess": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"source": {
"type": [
"string",
"null"
]
},
"target": {
"type": [
"string",
"null"
]
}
},
"required": [
"itemType"
],
"type": "object"
},
"ExternalAgentConfigImportParams": { "ExternalAgentConfigImportParams": {
"properties": { "properties": {
"migrationItems": { "migrationItems": {
@@ -927,7 +1019,7 @@
] ]
}, },
"providerId": { "providerId": {
"description": "Opaque provider identifier supplied by the caller for analytics attribution. This does not select the migration source.", "description": "Opaque provider identifier supplied by the caller for analytics attribution and import history display. This does not select the migration source.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -946,6 +1038,31 @@
], ],
"type": "object" "type": "object"
}, },
"ExternalAgentConfigImportTypeResult": {
"properties": {
"failures": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"successes": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"failures",
"itemType",
"successes"
],
"type": "object"
},
"ExternalAgentConfigMigrationItem": { "ExternalAgentConfigMigrationItem": {
"properties": { "properties": {
"cwd": { "cwd": {
@@ -7076,6 +7193,30 @@
"title": "ExternalAgentConfig/importRequest", "title": "ExternalAgentConfig/importRequest",
"type": "object" "type": "object"
}, },
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/recordHistory"
],
"title": "ExternalAgentConfig/import/recordHistoryRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ExternalAgentConfigImportHistoryRecordParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "ExternalAgentConfig/import/recordHistoryRequest",
"type": "object"
},
{ {
"properties": { "properties": {
"id": { "id": {
@@ -2195,6 +2195,30 @@
"title": "ExternalAgentConfig/importRequest", "title": "ExternalAgentConfig/importRequest",
"type": "object" "type": "object"
}, },
{
"properties": {
"id": {
"$ref": "#/definitions/v2/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/recordHistory"
],
"title": "ExternalAgentConfig/import/recordHistoryRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportHistoryRecordParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "ExternalAgentConfig/import/recordHistoryRequest",
"type": "object"
},
{ {
"properties": { "properties": {
"id": { "id": {
@@ -9741,6 +9765,12 @@
"importId": { "importId": {
"type": "string" "type": "string"
}, },
"providerId": {
"type": [
"string",
"null"
]
},
"successes": { "successes": {
"items": { "items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportItemTypeSuccess" "$ref": "#/definitions/v2/ExternalAgentConfigImportItemTypeSuccess"
@@ -9756,6 +9786,41 @@
], ],
"type": "object" "type": "object"
}, },
"ExternalAgentConfigImportHistoryRecordParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"itemTypeResults": {
"description": "Completed results grouped by imported item type.",
"items": {
"$ref": "#/definitions/v2/ExternalAgentConfigImportTypeResult"
},
"type": "array"
},
"providerId": {
"description": "Opaque provider identifier for the externally completed import.",
"type": "string"
}
},
"required": [
"itemTypeResults",
"providerId"
],
"title": "ExternalAgentConfigImportHistoryRecordParams",
"type": "object"
},
"ExternalAgentConfigImportHistoryRecordResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"importId": {
"type": "string"
}
},
"required": [
"importId"
],
"title": "ExternalAgentConfigImportHistoryRecordResponse",
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": { "ExternalAgentConfigImportItemTypeFailure": {
"properties": { "properties": {
"cwd": { "cwd": {
@@ -9845,7 +9910,7 @@
] ]
}, },
"providerId": { "providerId": {
"description": "Opaque provider identifier supplied by the caller for analytics attribution. This does not select the migration source.", "description": "Opaque provider identifier supplied by the caller for analytics attribution and import history display. This does not select the migration source.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -3334,6 +3334,30 @@
"title": "ExternalAgentConfig/importRequest", "title": "ExternalAgentConfig/importRequest",
"type": "object" "type": "object"
}, },
{
"properties": {
"id": {
"$ref": "#/definitions/RequestId"
},
"method": {
"enum": [
"externalAgentConfig/import/recordHistory"
],
"title": "ExternalAgentConfig/import/recordHistoryRequestMethod",
"type": "string"
},
"params": {
"$ref": "#/definitions/ExternalAgentConfigImportHistoryRecordParams"
}
},
"required": [
"id",
"method",
"params"
],
"title": "ExternalAgentConfig/import/recordHistoryRequest",
"type": "object"
},
{ {
"properties": { "properties": {
"id": { "id": {
@@ -5919,6 +5943,12 @@
"importId": { "importId": {
"type": "string" "type": "string"
}, },
"providerId": {
"type": [
"string",
"null"
]
},
"successes": { "successes": {
"items": { "items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess" "$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
@@ -5934,6 +5964,41 @@
], ],
"type": "object" "type": "object"
}, },
"ExternalAgentConfigImportHistoryRecordParams": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"itemTypeResults": {
"description": "Completed results grouped by imported item type.",
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
},
"providerId": {
"description": "Opaque provider identifier for the externally completed import.",
"type": "string"
}
},
"required": [
"itemTypeResults",
"providerId"
],
"title": "ExternalAgentConfigImportHistoryRecordParams",
"type": "object"
},
"ExternalAgentConfigImportHistoryRecordResponse": {
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"importId": {
"type": "string"
}
},
"required": [
"importId"
],
"title": "ExternalAgentConfigImportHistoryRecordResponse",
"type": "object"
},
"ExternalAgentConfigImportItemTypeFailure": { "ExternalAgentConfigImportItemTypeFailure": {
"properties": { "properties": {
"cwd": { "cwd": {
@@ -6023,7 +6088,7 @@
] ]
}, },
"providerId": { "providerId": {
"description": "Opaque provider identifier supplied by the caller for analytics attribution. This does not select the migration source.", "description": "Opaque provider identifier supplied by the caller for analytics attribution and import history display. This does not select the migration source.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -16,6 +16,12 @@
"importId": { "importId": {
"type": "string" "type": "string"
}, },
"providerId": {
"type": [
"string",
"null"
]
},
"successes": { "successes": {
"items": { "items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess" "$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
@@ -0,0 +1,136 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"ExternalAgentConfigImportItemTypeFailure": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"errorType": {
"type": [
"string",
"null"
]
},
"failureStage": {
"type": "string"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"message": {
"type": "string"
},
"source": {
"type": [
"string",
"null"
]
},
"subErrorType": {
"type": [
"string",
"null"
]
}
},
"required": [
"failureStage",
"itemType",
"message"
],
"type": "object"
},
"ExternalAgentConfigImportItemTypeSuccess": {
"properties": {
"cwd": {
"type": [
"string",
"null"
]
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"source": {
"type": [
"string",
"null"
]
},
"target": {
"type": [
"string",
"null"
]
}
},
"required": [
"itemType"
],
"type": "object"
},
"ExternalAgentConfigImportTypeResult": {
"properties": {
"failures": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeFailure"
},
"type": "array"
},
"itemType": {
"$ref": "#/definitions/ExternalAgentConfigMigrationItemType"
},
"successes": {
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportItemTypeSuccess"
},
"type": "array"
}
},
"required": [
"failures",
"itemType",
"successes"
],
"type": "object"
},
"ExternalAgentConfigMigrationItemType": {
"enum": [
"AGENTS_MD",
"CONFIG",
"SKILLS",
"PLUGINS",
"MCP_SERVER_CONFIG",
"SUBAGENTS",
"HOOKS",
"COMMANDS",
"MEMORY",
"SESSIONS"
],
"type": "string"
}
},
"properties": {
"itemTypeResults": {
"description": "Completed results grouped by imported item type.",
"items": {
"$ref": "#/definitions/ExternalAgentConfigImportTypeResult"
},
"type": "array"
},
"providerId": {
"description": "Opaque provider identifier for the externally completed import.",
"type": "string"
}
},
"required": [
"itemTypeResults",
"providerId"
],
"title": "ExternalAgentConfigImportHistoryRecordParams",
"type": "object"
}
@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"importId": {
"type": "string"
}
},
"required": [
"importId"
],
"title": "ExternalAgentConfigImportHistoryRecordResponse",
"type": "object"
}
@@ -218,7 +218,7 @@
] ]
}, },
"providerId": { "providerId": {
"description": "Opaque provider identifier supplied by the caller for analytics attribution. This does not select the migration source.", "description": "Opaque provider identifier supplied by the caller for analytics attribution and import history display. This does not select the migration source.",
"type": [ "type": [
"string", "string",
"null" "null"
@@ -22,6 +22,7 @@ import type { ConsumeAccountRateLimitResetCreditParams } from "./v2/ConsumeAccou
import type { ExperimentalFeatureEnablementSetParams } from "./v2/ExperimentalFeatureEnablementSetParams"; import type { ExperimentalFeatureEnablementSetParams } from "./v2/ExperimentalFeatureEnablementSetParams";
import type { ExperimentalFeatureListParams } from "./v2/ExperimentalFeatureListParams"; import type { ExperimentalFeatureListParams } from "./v2/ExperimentalFeatureListParams";
import type { ExternalAgentConfigDetectParams } from "./v2/ExternalAgentConfigDetectParams"; import type { ExternalAgentConfigDetectParams } from "./v2/ExternalAgentConfigDetectParams";
import type { ExternalAgentConfigImportHistoryRecordParams } from "./v2/ExternalAgentConfigImportHistoryRecordParams";
import type { ExternalAgentConfigImportParams } from "./v2/ExternalAgentConfigImportParams"; import type { ExternalAgentConfigImportParams } from "./v2/ExternalAgentConfigImportParams";
import type { FeedbackUploadParams } from "./v2/FeedbackUploadParams"; import type { FeedbackUploadParams } from "./v2/FeedbackUploadParams";
import type { FsCopyParams } from "./v2/FsCopyParams"; import type { FsCopyParams } from "./v2/FsCopyParams";
@@ -90,4 +91,4 @@ import type { WindowsSandboxSetupStartParams } from "./v2/WindowsSandboxSetupSta
/** /**
* Request from the client to the server. * Request from the client to the server.
*/ */
export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/delete", id: RequestId, params: ThreadDeleteParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/goal/set", id: RequestId, params: ThreadGoalSetParams, } | { "method": "thread/goal/get", id: RequestId, params: ThreadGoalGetParams, } | { "method": "thread/goal/clear", id: RequestId, params: ThreadGoalClearParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/approveGuardianDeniedAction", id: RequestId, params: ThreadApproveGuardianDeniedActionParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/extraRoots/set", id: RequestId, params: SkillsExtraRootsSetParams, } | { "method": "hooks/list", id: RequestId, params: HooksListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "marketplace/upgrade", id: RequestId, params: MarketplaceUpgradeParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/installed", id: RequestId, params: PluginInstalledParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "plugin/skill/read", id: RequestId, params: PluginSkillReadParams, } | { "method": "plugin/share/save", id: RequestId, params: PluginShareSaveParams, } | { "method": "plugin/share/updateTargets", id: RequestId, params: PluginShareUpdateTargetsParams, } | { "method": "plugin/share/list", id: RequestId, params: PluginShareListParams, } | { "method": "plugin/share/checkout", id: RequestId, params: PluginShareCheckoutParams, } | { "method": "plugin/share/delete", id: RequestId, params: PluginShareDeleteParams, } | { "method": "app/read", id: RequestId, params: AppsReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "app/installed", id: RequestId, params: AppsInstalledParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "modelProvider/capabilities/read", id: RequestId, params: ModelProviderCapabilitiesReadParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "permissionProfile/list", id: RequestId, params: PermissionProfileListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mLine truncated export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/delete", id: RequestId, params: ThreadDeleteParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/goal/set", id: RequestId, params: ThreadGoalSetParams, } | { "method": "thread/goal/get", id: RequestId, params: ThreadGoalGetParams, } | { "method": "thread/goal/clear", id: RequestId, params: ThreadGoalClearParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/approveGuardianDeniedAction", id: RequestId, params: ThreadApproveGuardianDeniedActionParams, } | { "method": "thread/rollback", id: RequestId, params: ThreadRollbackParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/extraRoots/set", id: RequestId, params: SkillsExtraRootsSetParams, } | { "method": "hooks/list", id: RequestId, params: HooksListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "marketplace/upgrade", id: RequestId, params: MarketplaceUpgradeParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/installed", id: RequestId, params: PluginInstalledParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "plugin/skill/read", id: RequestId, params: PluginSkillReadParams, } | { "method": "plugin/share/save", id: RequestId, params: PluginShareSaveParams, } | { "method": "plugin/share/updateTargets", id: RequestId, params: PluginShareUpdateTargetsParams, } | { "method": "plugin/share/list", id: RequestId, params: PluginShareListParams, } | { "method": "plugin/share/checkout", id: RequestId, params: PluginShareCheckoutParams, } | { "method": "plugin/share/delete", id: RequestId, params: PluginShareDeleteParams, } | { "method": "app/read", id: RequestId, params: AppsReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "app/installed", id: RequestId, params: AppsInstalledParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "modelProvider/capabilities/read", id: RequestId, params: ModelProviderCapabilitiesReadParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "permissionProfile/list", id: RequestId, params: PermissionProfileListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mLine truncated
@@ -4,4 +4,4 @@
import type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure"; import type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure";
import type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess"; import type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess";
export type ExternalAgentConfigImportHistory = { importId: string, completedAtMs: bigint, successes: Array<ExternalAgentConfigImportItemTypeSuccess>, failures: Array<ExternalAgentConfigImportItemTypeFailure>, }; export type ExternalAgentConfigImportHistory = { importId: string, providerId: string | null, completedAtMs: bigint, successes: Array<ExternalAgentConfigImportItemTypeSuccess>, failures: Array<ExternalAgentConfigImportItemTypeFailure>, };
@@ -0,0 +1,14 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { ExternalAgentConfigImportTypeResult } from "./ExternalAgentConfigImportTypeResult";
export type ExternalAgentConfigImportHistoryRecordParams = {
/**
* Opaque provider identifier for the externally completed import.
*/
providerId: string,
/**
* Completed results grouped by imported item type.
*/
itemTypeResults: Array<ExternalAgentConfigImportTypeResult>, };
@@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type ExternalAgentConfigImportHistoryRecordResponse = { importId: string, };
@@ -9,8 +9,8 @@ export type ExternalAgentConfigImportParams = { migrationItems: Array<ExternalAg
*/ */
source?: string | null, source?: string | null,
/** /**
* Opaque provider identifier supplied by the caller for analytics attribution. This does not * Opaque provider identifier supplied by the caller for analytics attribution and import
* select the migration source. * history display. This does not select the migration source.
*/ */
providerId?: string | null, providerId?: string | null,
/** /**
@@ -119,6 +119,8 @@ export type { ExternalAgentConfigDetectResponse } from "./ExternalAgentConfigDet
export type { ExternalAgentConfigImportCompletedNotification } from "./ExternalAgentConfigImportCompletedNotification"; export type { ExternalAgentConfigImportCompletedNotification } from "./ExternalAgentConfigImportCompletedNotification";
export type { ExternalAgentConfigImportHistoriesReadResponse } from "./ExternalAgentConfigImportHistoriesReadResponse"; export type { ExternalAgentConfigImportHistoriesReadResponse } from "./ExternalAgentConfigImportHistoriesReadResponse";
export type { ExternalAgentConfigImportHistory } from "./ExternalAgentConfigImportHistory"; export type { ExternalAgentConfigImportHistory } from "./ExternalAgentConfigImportHistory";
export type { ExternalAgentConfigImportHistoryRecordParams } from "./ExternalAgentConfigImportHistoryRecordParams";
export type { ExternalAgentConfigImportHistoryRecordResponse } from "./ExternalAgentConfigImportHistoryRecordResponse";
export type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure"; export type { ExternalAgentConfigImportItemTypeFailure } from "./ExternalAgentConfigImportItemTypeFailure";
export type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess"; export type { ExternalAgentConfigImportItemTypeSuccess } from "./ExternalAgentConfigImportItemTypeSuccess";
export type { ExternalAgentConfigImportParams } from "./ExternalAgentConfigImportParams"; export type { ExternalAgentConfigImportParams } from "./ExternalAgentConfigImportParams";
@@ -1155,6 +1155,11 @@ client_request_definitions! {
serialization: global("config"), serialization: global("config"),
response: v2::ExternalAgentConfigImportResponse, response: v2::ExternalAgentConfigImportResponse,
}, },
ExternalAgentConfigImportHistoryRecord => "externalAgentConfig/import/recordHistory" {
params: v2::ExternalAgentConfigImportHistoryRecordParams,
serialization: global("config"),
response: v2::ExternalAgentConfigImportHistoryRecordResponse,
},
ExternalAgentConfigImportHistoriesRead => "externalAgentConfig/import/readHistories" { ExternalAgentConfigImportHistoriesRead => "externalAgentConfig/import/readHistories" {
params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>, params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>,
serialization: global_shared_read("config"), serialization: global_shared_read("config"),
@@ -741,8 +741,8 @@ pub struct ExternalAgentConfigImportParams {
/// Optional identifier for the product that initiated the import. /// Optional identifier for the product that initiated the import.
#[ts(optional = nullable)] #[ts(optional = nullable)]
pub source: Option<String>, pub source: Option<String>,
/// Opaque provider identifier supplied by the caller for analytics attribution. This does not /// Opaque provider identifier supplied by the caller for analytics attribution and import
/// select the migration source. /// history display. This does not select the migration source.
#[ts(optional = nullable)] #[ts(optional = nullable)]
pub provider_id: Option<String>, pub provider_id: Option<String>,
/// Migration-source selector used to produce the migration items. Pass the same value to /// Migration-source selector used to produce the migration items. Pass the same value to
@@ -790,11 +790,29 @@ pub struct ExternalAgentConfigImportTypeResult {
pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>, pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportHistoryRecordParams {
/// Opaque provider identifier for the externally completed import.
pub provider_id: String,
/// Completed results grouped by imported item type.
pub item_type_results: Vec<ExternalAgentConfigImportTypeResult>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportHistoryRecordResponse {
pub import_id: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")] #[ts(export_to = "v2/")]
pub struct ExternalAgentConfigImportHistory { pub struct ExternalAgentConfigImportHistory {
pub import_id: String, pub import_id: String,
pub provider_id: Option<String>,
pub completed_at_ms: i64, pub completed_at_ms: i64,
pub successes: Vec<ExternalAgentConfigImportItemTypeSuccess>, pub successes: Vec<ExternalAgentConfigImportItemTypeSuccess>,
pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>, pub failures: Vec<ExternalAgentConfigImportItemTypeFailure>,
@@ -14,10 +14,13 @@ use codex_app_server_protocol::ExternalAgentConfigDetectParams;
use codex_app_server_protocol::ExternalAgentConfigDetectResponse; use codex_app_server_protocol::ExternalAgentConfigDetectResponse;
use codex_app_server_protocol::ExternalAgentConfigImportCompletedNotification; use codex_app_server_protocol::ExternalAgentConfigImportCompletedNotification;
use codex_app_server_protocol::ExternalAgentConfigImportHistoriesReadResponse; use codex_app_server_protocol::ExternalAgentConfigImportHistoriesReadResponse;
use codex_app_server_protocol::ExternalAgentConfigImportHistoryRecordParams;
use codex_app_server_protocol::ExternalAgentConfigImportHistoryRecordResponse;
use codex_app_server_protocol::ExternalAgentConfigImportItemTypeFailure as ProtocolImportFailure; use codex_app_server_protocol::ExternalAgentConfigImportItemTypeFailure as ProtocolImportFailure;
use codex_app_server_protocol::ExternalAgentConfigImportParams; use codex_app_server_protocol::ExternalAgentConfigImportParams;
use codex_app_server_protocol::ExternalAgentConfigImportProgressNotification; use codex_app_server_protocol::ExternalAgentConfigImportProgressNotification;
use codex_app_server_protocol::ExternalAgentConfigImportResponse; use codex_app_server_protocol::ExternalAgentConfigImportResponse;
use codex_app_server_protocol::ExternalAgentConfigImportTypeResult as ProtocolImportTypeResult;
use codex_app_server_protocol::ExternalAgentConfigMigrationItem; use codex_app_server_protocol::ExternalAgentConfigMigrationItem;
use codex_app_server_protocol::ExternalAgentConfigMigrationItemType; use codex_app_server_protocol::ExternalAgentConfigMigrationItemType;
use codex_app_server_protocol::ExternalAgentImportedConnectorCandidate; use codex_app_server_protocol::ExternalAgentImportedConnectorCandidate;
@@ -172,7 +175,7 @@ impl ExternalAgentConfigRequestProcessor {
} }
let import_id = Uuid::new_v4().to_string(); let import_id = Uuid::new_v4().to_string();
let analytics_source = params.source.clone().unwrap_or_default(); let analytics_source = params.source.clone().unwrap_or_default();
let provider_id = params.provider_id.clone().unwrap_or_default(); let provider_id = params.provider_id.clone();
let migration_service = self let migration_service = self
.migration_service .migration_service
.with_migration_source(params.migration_source.as_deref()); .with_migration_source(params.migration_source.as_deref());
@@ -378,6 +381,27 @@ impl ExternalAgentConfigRequestProcessor {
Ok(ExternalAgentConfigImportHistoriesReadResponse { data, connectors }) Ok(ExternalAgentConfigImportHistoriesReadResponse { data, connectors })
} }
pub(crate) async fn record_import_history(
&self,
params: ExternalAgentConfigImportHistoryRecordParams,
) -> Result<ExternalAgentConfigImportHistoryRecordResponse, JSONRPCErrorError> {
let state_db = self
.state_db
.as_ref()
.ok_or_else(|| internal_error("state database is unavailable"))?;
let import_id = Uuid::new_v4().to_string();
record_import_history(
state_db,
import_id.as_str(),
Some(params.provider_id.as_str()),
&params.item_type_results,
)
.await
.map_err(|err| internal_error(format!("failed to record import history: {err}")))?;
Ok(ExternalAgentConfigImportHistoryRecordResponse { import_id })
}
fn validate_pending_session_imports( fn validate_pending_session_imports(
&self, &self,
params: &ExternalAgentConfigImportParams, params: &ExternalAgentConfigImportParams,
@@ -483,7 +507,7 @@ async fn send_completed_import_notification(
analytics_events_client: &AnalyticsEventsClient, analytics_events_client: &AnalyticsEventsClient,
import_id: String, import_id: String,
analytics_source: String, analytics_source: String,
provider_id: String, provider_id: Option<String>,
item_results: &[CoreImportItemResult], item_results: &[CoreImportItemResult],
) { ) {
let notification = completed_notification(import_id, item_results); let notification = completed_notification(import_id, item_results);
@@ -491,11 +515,13 @@ async fn send_completed_import_notification(
track_completed_import_notification( track_completed_import_notification(
analytics_events_client, analytics_events_client,
&analytics_source, &analytics_source,
&provider_id, provider_id.as_deref().unwrap_or_default(),
&notification, &notification,
); );
if let Some(state_db) = state_db if let Some(state_db) = state_db
&& let Err(err) = record_completed_import_notification(state_db, &notification).await && let Err(err) =
record_completed_import_notification(state_db, provider_id.as_deref(), &notification)
.await
{ {
tracing::warn!( tracing::warn!(
import_id = %notification.import_id, import_id = %notification.import_id,
@@ -586,10 +612,25 @@ fn analytics_migration_item_type(item_type: ExternalAgentConfigMigrationItemType
async fn record_completed_import_notification( async fn record_completed_import_notification(
state_db: &StateDbHandle, state_db: &StateDbHandle,
provider_id: Option<&str>,
notification: &ExternalAgentConfigImportCompletedNotification, notification: &ExternalAgentConfigImportCompletedNotification,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let successes = notification record_import_history(
.item_type_results state_db,
notification.import_id.as_str(),
provider_id,
&notification.item_type_results,
)
.await
}
async fn record_import_history(
state_db: &StateDbHandle,
import_id: &str,
provider_id: Option<&str>,
item_type_results: &[ProtocolImportTypeResult],
) -> anyhow::Result<()> {
let successes = item_type_results
.iter() .iter()
.flat_map(|type_result| type_result.successes.iter()) .flat_map(|type_result| type_result.successes.iter())
.map(|success| { .map(|success| {
@@ -601,8 +642,7 @@ async fn record_completed_import_notification(
}) })
}) })
.collect::<anyhow::Result<Vec<_>>>()?; .collect::<anyhow::Result<Vec<_>>>()?;
let failures = notification let failures = item_type_results
.item_type_results
.iter() .iter()
.flat_map(|type_result| type_result.failures.iter()) .flat_map(|type_result| type_result.failures.iter())
.map(|failure| { .map(|failure| {
@@ -619,7 +659,8 @@ async fn record_completed_import_notification(
.collect::<anyhow::Result<Vec<_>>>()?; .collect::<anyhow::Result<Vec<_>>>()?;
state_db state_db
.record_external_agent_config_import_completed( .record_external_agent_config_import_completed(
notification.import_id.as_str(), import_id,
provider_id,
&successes, &successes,
&failures, &failures,
) )
@@ -210,6 +210,7 @@ pub(super) fn protocol_import_history(
Ok(ExternalAgentConfigImportHistory { Ok(ExternalAgentConfigImportHistory {
import_id: record.import_id, import_id: record.import_id,
provider_id: record.provider_id,
completed_at_ms: record.completed_at_ms, completed_at_ms: record.completed_at_ms,
successes, successes,
failures, failures,
@@ -896,6 +896,11 @@ impl MessageProcessor {
.import(request_id.clone(), params) .import(request_id.clone(), params)
.await .await
.map(|()| None), .map(|()| None),
ClientRequest::ExternalAgentConfigImportHistoryRecord { params, .. } => self
.external_agent_config_processor
.record_import_history(params)
.await
.map(|response| Some(response.into())),
ClientRequest::ExternalAgentConfigImportHistoriesRead { .. } => self ClientRequest::ExternalAgentConfigImportHistoriesRead { .. } => self
.external_agent_config_processor .external_agent_config_processor
.read_import_histories() .read_import_histories()
@@ -10,6 +10,7 @@ use app_test_support::write_chatgpt_auth;
use codex_app_server_protocol::ExternalAgentConfigDetectResponse; use codex_app_server_protocol::ExternalAgentConfigDetectResponse;
use codex_app_server_protocol::ExternalAgentConfigImportCompletedNotification; use codex_app_server_protocol::ExternalAgentConfigImportCompletedNotification;
use codex_app_server_protocol::ExternalAgentConfigImportHistoriesReadResponse; use codex_app_server_protocol::ExternalAgentConfigImportHistoriesReadResponse;
use codex_app_server_protocol::ExternalAgentConfigImportHistoryRecordResponse;
use codex_app_server_protocol::ExternalAgentConfigImportProgressNotification; use codex_app_server_protocol::ExternalAgentConfigImportProgressNotification;
use codex_app_server_protocol::ExternalAgentConfigImportResponse; use codex_app_server_protocol::ExternalAgentConfigImportResponse;
use codex_app_server_protocol::ExternalAgentConfigMigrationItemType; use codex_app_server_protocol::ExternalAgentConfigMigrationItemType;
@@ -590,6 +591,73 @@ async fn external_agent_config_import_sends_completion_notification_for_sync_onl
Ok(()) Ok(())
} }
#[tokio::test]
async fn external_agent_config_records_externally_completed_import_history() -> Result<()> {
let codex_home = TempDir::new()?;
let sqlite_home = TempDir::new()?;
let home_dir = codex_home.path().display().to_string();
let sqlite_home_dir = sqlite_home.path().display().to_string();
let mut mcp = TestAppServer::builder()
.with_codex_home(codex_home.path())
.without_auto_env()
.with_env_overrides(&[
("HOME", Some(home_dir.as_str())),
("CODEX_SQLITE_HOME", Some(sqlite_home_dir.as_str())),
])
.build_initialized_with_timeout(DEFAULT_TIMEOUT)
.await?;
let request_id = mcp
.send_raw_request(
"externalAgentConfig/import/recordHistory",
Some(serde_json::json!({
"providerId": "external-provider",
"itemTypeResults": [{
"itemType": "SESSIONS",
"successes": [{
"itemType": "SESSIONS",
"cwd": "/repo",
"source": "/source/session.jsonl",
"target": "thread-1",
}],
"failures": [],
}],
})),
)
.await?;
let record_response: ExternalAgentConfigImportHistoryRecordResponse =
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
assert!(!record_response.import_id.is_empty());
let request_id = mcp
.send_raw_request(
"externalAgentConfig/import/readHistories",
/*params*/ None,
)
.await?;
let history_response: ExternalAgentConfigImportHistoriesReadResponse =
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
let entry = history_response
.data
.iter()
.find(|entry| entry.import_id == record_response.import_id)
.expect("externally completed import history entry should be available");
assert_eq!(entry.provider_id.as_deref(), Some("external-provider"));
assert!(entry.completed_at_ms > 0);
assert_eq!(
serde_json::to_value(&entry.successes)?,
serde_json::json!([{
"itemType": "SESSIONS",
"cwd": "/repo",
"source": "/source/session.jsonl",
"target": "thread-1",
}])
);
assert_eq!(entry.failures, Vec::new());
Ok(())
}
#[tokio::test] #[tokio::test]
async fn external_agent_memory_import_requires_feature_config() -> Result<()> { async fn external_agent_memory_import_requires_feature_config() -> Result<()> {
let codex_home = TempDir::new()?; let codex_home = TempDir::new()?;
@@ -0,0 +1,2 @@
ALTER TABLE external_agent_config_imports
ADD COLUMN provider_id TEXT;
@@ -35,6 +35,7 @@ pub struct ExternalAgentConfigImportDetailsRecord {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ExternalAgentConfigImportHistoryRecord { pub struct ExternalAgentConfigImportHistoryRecord {
pub import_id: String, pub import_id: String,
pub provider_id: Option<String>,
pub completed_at_ms: i64, pub completed_at_ms: i64,
pub successes: Vec<ExternalAgentConfigImportSuccessRecord>, pub successes: Vec<ExternalAgentConfigImportSuccessRecord>,
pub failures: Vec<ExternalAgentConfigImportFailureRecord>, pub failures: Vec<ExternalAgentConfigImportFailureRecord>,
@@ -44,6 +45,7 @@ impl StateRuntime {
pub async fn record_external_agent_config_import_completed( pub async fn record_external_agent_config_import_completed(
&self, &self,
import_id: &str, import_id: &str,
provider_id: Option<&str>,
successes: &[ExternalAgentConfigImportSuccessRecord], successes: &[ExternalAgentConfigImportSuccessRecord],
failures: &[ExternalAgentConfigImportFailureRecord], failures: &[ExternalAgentConfigImportFailureRecord],
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
@@ -51,17 +53,20 @@ impl StateRuntime {
r#" r#"
INSERT INTO external_agent_config_imports ( INSERT INTO external_agent_config_imports (
import_id, import_id,
provider_id,
completed_at_ms, completed_at_ms,
successes, successes,
failures failures
) VALUES (?, ?, ?, ?) ) VALUES (?, ?, ?, ?, ?)
ON CONFLICT(import_id) DO UPDATE SET ON CONFLICT(import_id) DO UPDATE SET
provider_id = excluded.provider_id,
completed_at_ms = excluded.completed_at_ms, completed_at_ms = excluded.completed_at_ms,
successes = excluded.successes, successes = excluded.successes,
failures = excluded.failures failures = excluded.failures
"#, "#,
) )
.bind(import_id) .bind(import_id)
.bind(provider_id)
.bind(datetime_to_epoch_millis(Utc::now())) .bind(datetime_to_epoch_millis(Utc::now()))
.bind(serde_json::to_string(successes)?) .bind(serde_json::to_string(successes)?)
.bind(serde_json::to_string(failures)?) .bind(serde_json::to_string(failures)?)
@@ -106,6 +111,7 @@ WHERE import_id = ?
r#" r#"
SELECT SELECT
import_id, import_id,
provider_id,
completed_at_ms, completed_at_ms,
successes, successes,
failures failures
@@ -119,11 +125,13 @@ ORDER BY completed_at_ms DESC, import_id ASC
rows.into_iter() rows.into_iter()
.map(|row| { .map(|row| {
let import_id: String = row.try_get("import_id")?; let import_id: String = row.try_get("import_id")?;
let provider_id: Option<String> = row.try_get("provider_id")?;
let completed_at_ms: i64 = row.try_get("completed_at_ms")?; let completed_at_ms: i64 = row.try_get("completed_at_ms")?;
let successes: String = row.try_get("successes")?; let successes: String = row.try_get("successes")?;
let failures: String = row.try_get("failures")?; let failures: String = row.try_get("failures")?;
Ok(ExternalAgentConfigImportHistoryRecord { Ok(ExternalAgentConfigImportHistoryRecord {
import_id, import_id,
provider_id,
completed_at_ms, completed_at_ms,
successes: serde_json::from_str(&successes)?, successes: serde_json::from_str(&successes)?,
failures: serde_json::from_str(&failures)?, failures: serde_json::from_str(&failures)?,
@@ -9,6 +9,7 @@ async fn records_completion_by_import_id() -> anyhow::Result<()> {
runtime runtime
.record_external_agent_config_import_completed( .record_external_agent_config_import_completed(
"import-1", "import-1",
Some("provider-1"),
&[ExternalAgentConfigImportSuccessRecord { &[ExternalAgentConfigImportSuccessRecord {
item_type: "CONFIG".to_string(), item_type: "CONFIG".to_string(),
cwd: None, cwd: None,
@@ -21,6 +22,7 @@ async fn records_completion_by_import_id() -> anyhow::Result<()> {
runtime runtime
.record_external_agent_config_import_completed( .record_external_agent_config_import_completed(
"import-1", "import-1",
Some("provider-2"),
&[ &[
ExternalAgentConfigImportSuccessRecord { ExternalAgentConfigImportSuccessRecord {
item_type: "CONFIG".to_string(), item_type: "CONFIG".to_string(),
@@ -84,6 +86,7 @@ async fn records_completion_by_import_id() -> anyhow::Result<()> {
.into_iter() .into_iter()
.map(|record| ( .map(|record| (
record.import_id, record.import_id,
record.provider_id,
record.successes, record.successes,
record.failures, record.failures,
record.completed_at_ms > 0 record.completed_at_ms > 0
@@ -91,6 +94,7 @@ async fn records_completion_by_import_id() -> anyhow::Result<()> {
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
vec![( vec![(
"import-1".to_string(), "import-1".to_string(),
Some("provider-2".to_string()),
vec![ vec![
ExternalAgentConfigImportSuccessRecord { ExternalAgentConfigImportSuccessRecord {
item_type: "CONFIG".to_string(), item_type: "CONFIG".to_string(),
@@ -126,10 +130,20 @@ async fn reads_all_history_records() -> anyhow::Result<()> {
let runtime = StateRuntime::init(unique_temp_dir(), "test-provider".to_string()).await?; let runtime = StateRuntime::init(unique_temp_dir(), "test-provider".to_string()).await?;
runtime runtime
.record_external_agent_config_import_completed("import-1", &[], &[]) .record_external_agent_config_import_completed(
"import-1",
/*provider_id*/ None,
&[],
&[],
)
.await?; .await?;
runtime runtime
.record_external_agent_config_import_completed("import-2", &[], &[]) .record_external_agent_config_import_completed(
"import-2",
/*provider_id*/ None,
&[],
&[],
)
.await?; .await?;
let mut records = runtime let mut records = runtime