@openagentpack/sdk 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +85 -26
- package/dist/index.js +801 -177
- package/dist/session-events.d.ts +1 -1
- package/package.json +1 -1
- package/dist/{session-event-mzuENtyH.d.ts → session-event--Mxe1bnT.d.ts} +37 -37
package/dist/index.js
CHANGED
|
@@ -58,10 +58,10 @@ var BaseApiClient = class {
|
|
|
58
58
|
if (this.isConflict(res.status, body)) throw new ConflictError(res.status, body, this.errorPrefix);
|
|
59
59
|
throw new ApiError(res.status, body, this.errorPrefix);
|
|
60
60
|
}
|
|
61
|
-
async post(path, body) {
|
|
61
|
+
async post(path, body, options) {
|
|
62
62
|
const res = await resolveFetch()(`${this.baseUrl}${path}`, {
|
|
63
63
|
method: "POST",
|
|
64
|
-
headers: this.headers(),
|
|
64
|
+
headers: { ...this.headers(), ...options?.headers },
|
|
65
65
|
body: JSON.stringify(body)
|
|
66
66
|
});
|
|
67
67
|
await this.throwIfError(res);
|
|
@@ -2059,6 +2059,13 @@ function mapEnvironment2(name, decl, projectName) {
|
|
|
2059
2059
|
metadata: injectMetadata(decl.metadata, projectName, name)
|
|
2060
2060
|
};
|
|
2061
2061
|
}
|
|
2062
|
+
function mapForwardEnvironment(name, decl, projectName) {
|
|
2063
|
+
const body = mapEnvironment2(name, decl, projectName);
|
|
2064
|
+
const config = { ...body.config };
|
|
2065
|
+
delete config.networking;
|
|
2066
|
+
body.config = config;
|
|
2067
|
+
return body;
|
|
2068
|
+
}
|
|
2062
2069
|
function mapVault(name, decl, projectName) {
|
|
2063
2070
|
const body = { display_name: decl.display_name };
|
|
2064
2071
|
if (projectName) body.metadata = injectMetadata(decl.metadata, projectName, name);
|
|
@@ -2373,10 +2380,12 @@ function mapForwardTemplate(name, decl, refs, projectName) {
|
|
|
2373
2380
|
environment_id: refs.environment_id,
|
|
2374
2381
|
vault_ids: refs.vault_ids
|
|
2375
2382
|
};
|
|
2383
|
+
body.files = Object.fromEntries((refs.file_ids ?? []).map((id) => [id, { enabled: true }]));
|
|
2376
2384
|
if (refs.tunnel_id) body.tunnel_id = refs.tunnel_id;
|
|
2377
2385
|
if (projectName) body.metadata = injectMetadata(decl.metadata, projectName, name);
|
|
2378
2386
|
else body.metadata = decl.metadata ?? {};
|
|
2379
2387
|
if (decl.environment_variables) body.environment_variables = decl.environment_variables;
|
|
2388
|
+
if (decl.managed_tool_config) body.managed_tool_config = decl.managed_tool_config;
|
|
2380
2389
|
if (decl.tools) {
|
|
2381
2390
|
body.tools = [
|
|
2382
2391
|
{
|
|
@@ -2565,6 +2574,7 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2565
2574
|
client;
|
|
2566
2575
|
memoryApi;
|
|
2567
2576
|
forwardClient;
|
|
2577
|
+
forwardMemoryApi;
|
|
2568
2578
|
projectName;
|
|
2569
2579
|
forwardSessionIds = /* @__PURE__ */ new Set();
|
|
2570
2580
|
constructor(apiKey, gateway, projectName, forwardGateway) {
|
|
@@ -2586,6 +2596,19 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2586
2596
|
apiKey,
|
|
2587
2597
|
gateway: forwardGateway ?? deriveForwardGateway(gateway)
|
|
2588
2598
|
});
|
|
2599
|
+
this.forwardMemoryApi = new ProviderMemoryApi(this.forwardClient, {
|
|
2600
|
+
pathStyle: "relative",
|
|
2601
|
+
cursorParam: "after_id",
|
|
2602
|
+
updatePrecondition: "content_sha256",
|
|
2603
|
+
prefixParam: "prefix",
|
|
2604
|
+
versionsSegment: "versions",
|
|
2605
|
+
storeMetadataMode: "merge_patch",
|
|
2606
|
+
supportsView: false,
|
|
2607
|
+
supportsMemoryMetadata: true,
|
|
2608
|
+
supportsPathUpdate: false,
|
|
2609
|
+
supportsDeletePrecondition: false,
|
|
2610
|
+
supportsIncludeArchived: true
|
|
2611
|
+
});
|
|
2589
2612
|
this.projectName = projectName ?? "";
|
|
2590
2613
|
}
|
|
2591
2614
|
async validate() {
|
|
@@ -2600,7 +2623,7 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2600
2623
|
file: "/files",
|
|
2601
2624
|
deployment: "/deployments"
|
|
2602
2625
|
};
|
|
2603
|
-
async findResource(type, name, id) {
|
|
2626
|
+
async findResource(type, name, id, mode) {
|
|
2604
2627
|
if (type === "template") {
|
|
2605
2628
|
const raw2 = await locateRemote(this.forwardClient, "/templates", name, id, (item) => item.status !== "archived");
|
|
2606
2629
|
return raw2 ? toRemoteResource(raw2) : null;
|
|
@@ -2620,7 +2643,14 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2620
2643
|
const raw2 = await locateRemote(this.forwardClient, "/channels", name, id, () => true);
|
|
2621
2644
|
return raw2 ? toRemoteResource(raw2) : null;
|
|
2622
2645
|
}
|
|
2623
|
-
|
|
2646
|
+
if (type === "environment" && id && mode === "auto") {
|
|
2647
|
+
const managed = await locateRemote(this.client, "/environments", name, id, notArchived);
|
|
2648
|
+
if (managed) return toRemoteResource(managed);
|
|
2649
|
+
const forward = await locateRemote(this.forwardClient, "/environments", name, id, notArchived);
|
|
2650
|
+
return forward ? toRemoteResource(forward) : null;
|
|
2651
|
+
}
|
|
2652
|
+
const client = mode === "forward" && (type === "environment" || type === "skill" || type === "vault" || type === "memory_store" || type === "file") ? this.forwardClient : this.client;
|
|
2653
|
+
const raw = await locateRemote(client, _QoderAdapter.ENDPOINT_MAP[type], name, id, notArchived);
|
|
2624
2654
|
return raw ? toRemoteResource(raw) : null;
|
|
2625
2655
|
}
|
|
2626
2656
|
async listAgents(filter) {
|
|
@@ -2764,16 +2794,21 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2764
2794
|
}
|
|
2765
2795
|
if (type === "channel") {
|
|
2766
2796
|
const channelConfig = raw.channel_config ?? {};
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2797
|
+
const mode = raw.identity_resolution?.mode ?? "fixed";
|
|
2798
|
+
const normalized = {
|
|
2799
|
+
identity_resolution: { mode },
|
|
2770
2800
|
channel_type: raw.channel_type,
|
|
2771
2801
|
name: raw.name,
|
|
2772
2802
|
enabled: raw.enabled,
|
|
2773
2803
|
channel_config: {
|
|
2774
2804
|
response_options: channelConfig.response_options ?? {}
|
|
2775
2805
|
}
|
|
2776
|
-
}
|
|
2806
|
+
};
|
|
2807
|
+
if (mode === "fixed") {
|
|
2808
|
+
normalized.identity_id = raw.identity_id;
|
|
2809
|
+
normalized.template_id = raw.template_id;
|
|
2810
|
+
}
|
|
2811
|
+
return compactDeep(normalized);
|
|
2777
2812
|
}
|
|
2778
2813
|
return compactDeep({
|
|
2779
2814
|
description: raw.description,
|
|
@@ -2784,24 +2819,29 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2784
2819
|
metadata: stripAgentsMetadata(raw.metadata)
|
|
2785
2820
|
});
|
|
2786
2821
|
}
|
|
2787
|
-
async createEnvironment(name, decl) {
|
|
2788
|
-
const body = mapEnvironment2(name, decl, this.projectName);
|
|
2789
|
-
const res = await this.client.post("/environments", body);
|
|
2822
|
+
async createEnvironment(name, decl, mode = "managed") {
|
|
2823
|
+
const body = mode === "forward" ? mapForwardEnvironment(name, decl, this.projectName) : mapEnvironment2(name, decl, this.projectName);
|
|
2824
|
+
const res = await (mode === "forward" ? this.forwardClient : this.client).post("/environments", body);
|
|
2790
2825
|
return toRemoteResource(res);
|
|
2791
2826
|
}
|
|
2792
|
-
async updateEnvironment(id, name, decl) {
|
|
2793
|
-
const body = mapEnvironment2(name, decl, this.projectName);
|
|
2794
|
-
const
|
|
2827
|
+
async updateEnvironment(id, name, decl, mode = "managed") {
|
|
2828
|
+
const body = mode === "forward" ? mapForwardEnvironment(name, decl, this.projectName) : mapEnvironment2(name, decl, this.projectName);
|
|
2829
|
+
const client = mode === "forward" ? this.forwardClient : this.client;
|
|
2830
|
+
const current = await client.get(`/environments/${id}`);
|
|
2795
2831
|
const currentMetadata = current.metadata ?? {};
|
|
2796
2832
|
const metadata = { ...body.metadata ?? {} };
|
|
2797
2833
|
for (const key of Object.keys(currentMetadata)) {
|
|
2798
2834
|
if (!key.startsWith("agents.") && !(key in metadata)) metadata[key] = null;
|
|
2799
2835
|
}
|
|
2800
2836
|
body.metadata = metadata;
|
|
2801
|
-
const res = await
|
|
2837
|
+
const res = await client.post(`/environments/${id}`, body);
|
|
2802
2838
|
return toRemoteResource(res);
|
|
2803
2839
|
}
|
|
2804
|
-
async deleteEnvironment(id, cascade = false) {
|
|
2840
|
+
async deleteEnvironment(id, cascade = false, mode = "managed") {
|
|
2841
|
+
if (mode === "forward") {
|
|
2842
|
+
await this.forwardClient.delete(`/environments/${id}`);
|
|
2843
|
+
return;
|
|
2844
|
+
}
|
|
2805
2845
|
try {
|
|
2806
2846
|
await this.client.delete(`/environments/${id}`);
|
|
2807
2847
|
return;
|
|
@@ -2828,17 +2868,18 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2828
2868
|
await this.client.post(`/environments/${id}/archive`, {});
|
|
2829
2869
|
}
|
|
2830
2870
|
}
|
|
2831
|
-
async createVault(name, decl) {
|
|
2871
|
+
async createVault(name, decl, mode = "managed") {
|
|
2872
|
+
const client = mode === "forward" ? this.forwardClient : this.client;
|
|
2832
2873
|
const body = mapVault(name, decl, this.projectName);
|
|
2833
|
-
const res = await
|
|
2874
|
+
const res = await client.post("/vaults", body);
|
|
2834
2875
|
const vaultId = res.id;
|
|
2835
2876
|
for (const cred of decl.credentials ?? []) {
|
|
2836
|
-
await
|
|
2877
|
+
await client.post(`/vaults/${vaultId}/credentials`, mapCredential(cred));
|
|
2837
2878
|
}
|
|
2838
2879
|
return toRemoteResource(res);
|
|
2839
2880
|
}
|
|
2840
|
-
async deleteVault(id) {
|
|
2841
|
-
await this.client.delete(`/vaults/${id}`);
|
|
2881
|
+
async deleteVault(id, mode = "managed") {
|
|
2882
|
+
await (mode === "forward" ? this.forwardClient : this.client).delete(`/vaults/${id}`);
|
|
2842
2883
|
}
|
|
2843
2884
|
async exportResources(type) {
|
|
2844
2885
|
return exportRemoteResources(this.client, type, {
|
|
@@ -2849,17 +2890,24 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2849
2890
|
agentToDecl: agentToDecl2
|
|
2850
2891
|
});
|
|
2851
2892
|
}
|
|
2852
|
-
async createSkill(name, decl, files) {
|
|
2893
|
+
async createSkill(name, decl, files, mode = "managed") {
|
|
2853
2894
|
const formData = await buildSkillFormData(name, decl, files);
|
|
2854
|
-
const res = await this.client.postFormData(
|
|
2895
|
+
const res = await (mode === "forward" ? this.forwardClient : this.client).postFormData(
|
|
2896
|
+
"/skills",
|
|
2897
|
+
formData
|
|
2898
|
+
);
|
|
2855
2899
|
return toRemoteResource(res);
|
|
2856
2900
|
}
|
|
2857
|
-
async updateSkill(id, name, decl, files) {
|
|
2858
|
-
|
|
2859
|
-
|
|
2901
|
+
async updateSkill(id, name, decl, files, mode = "managed") {
|
|
2902
|
+
const client = mode === "forward" ? this.forwardClient : this.client;
|
|
2903
|
+
const packageName = skillNameFromFiles(files) ?? name;
|
|
2904
|
+
const formData = await buildSkillFormData(packageName, decl, files, "files", false, true);
|
|
2905
|
+
await client.postFormData(`/skills/${id}/versions`, formData);
|
|
2906
|
+
const current = await client.get(`/skills/${id}`);
|
|
2907
|
+
return toRemoteResource(current);
|
|
2860
2908
|
}
|
|
2861
|
-
async deleteSkill(id) {
|
|
2862
|
-
await this.client.delete(`/skills/${id}`);
|
|
2909
|
+
async deleteSkill(id, mode = "managed") {
|
|
2910
|
+
await (mode === "forward" ? this.forwardClient : this.client).delete(`/skills/${id}`);
|
|
2863
2911
|
}
|
|
2864
2912
|
async createAgent(name, decl, refs) {
|
|
2865
2913
|
const body = mapAgent2(name, decl, refs, void 0, this.projectName);
|
|
@@ -2876,21 +2924,89 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2876
2924
|
await this.client.delete(`/agents/${id}`);
|
|
2877
2925
|
}
|
|
2878
2926
|
async createTemplate(name, decl, refs) {
|
|
2879
|
-
await this.registerForwardVaults(refs.vault_ids);
|
|
2880
2927
|
const body = mapForwardTemplate(name, decl, refs, this.projectName);
|
|
2881
2928
|
const res = await this.forwardClient.post("/templates", body);
|
|
2929
|
+
await this.reconcileForwardMemoryMounts(res.id, refs);
|
|
2882
2930
|
return toRemoteResource(res);
|
|
2883
2931
|
}
|
|
2884
2932
|
async updateTemplate(id, name, decl, refs) {
|
|
2885
|
-
await this.registerForwardVaults(refs.vault_ids);
|
|
2886
2933
|
const body = mapForwardTemplate(name, decl, refs, this.projectName);
|
|
2887
2934
|
if (!refs.tunnel_id) body.tunnel_id = null;
|
|
2888
2935
|
const res = await this.forwardClient.post(`/templates/${id}`, body);
|
|
2936
|
+
await this.reconcileForwardMemoryMounts(id, refs);
|
|
2889
2937
|
return toRemoteResource(res);
|
|
2890
2938
|
}
|
|
2891
|
-
async archiveTemplate(id) {
|
|
2939
|
+
async archiveTemplate(id, ownedMemoryStoreIds = []) {
|
|
2940
|
+
const owned = new Set(ownedMemoryStoreIds);
|
|
2941
|
+
if (owned.size > 0) {
|
|
2942
|
+
for (const identity of await this.forwardClient.getAllPaged("/identities")) {
|
|
2943
|
+
if (typeof identity.id !== "string") continue;
|
|
2944
|
+
const path = `/identities/${identity.id}/templates/${id}/memory_stores`;
|
|
2945
|
+
try {
|
|
2946
|
+
const mounts = await this.forwardClient.get(path);
|
|
2947
|
+
for (const mount of mounts.data ?? []) {
|
|
2948
|
+
const storeId = mount.memory_store_id;
|
|
2949
|
+
if (mount.system_managed !== true && typeof storeId === "string" && owned.has(storeId)) {
|
|
2950
|
+
await this.forwardClient.delete(`${path}/${storeId}`);
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
} catch (error) {
|
|
2954
|
+
if (!ApiError.isNotFound(error)) throw error;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2892
2958
|
await this.forwardClient.post(`/templates/${id}/archive`, {});
|
|
2893
2959
|
}
|
|
2960
|
+
async reconcileForwardMemoryMounts(templateId, refs) {
|
|
2961
|
+
if (refs.memory_store_ids === void 0) return;
|
|
2962
|
+
const desired = new Set(refs.memory_store_ids ?? []);
|
|
2963
|
+
if (!refs.identity_id) {
|
|
2964
|
+
if (desired.size > 0) throw new UserError("Qoder Forward Memory Store mounts require an Identity.");
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
const path = `/identities/${refs.identity_id}/templates/${templateId}/memory_stores`;
|
|
2968
|
+
const current = await this.forwardClient.get(path);
|
|
2969
|
+
const explicit = (current.data ?? []).filter((mount) => mount.system_managed !== true);
|
|
2970
|
+
const owned = new Set(refs.owned_memory_store_ids ?? refs.memory_store_ids ?? []);
|
|
2971
|
+
for (const mount of explicit) {
|
|
2972
|
+
const storeId = mount.memory_store_id;
|
|
2973
|
+
if (typeof storeId === "string" && owned.has(storeId) && !desired.has(storeId)) {
|
|
2974
|
+
await this.forwardClient.delete(`${path}/${storeId}`);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
const mounted = new Set(
|
|
2978
|
+
explicit.map((mount) => mount.memory_store_id).filter((id) => typeof id === "string")
|
|
2979
|
+
);
|
|
2980
|
+
for (const memoryStoreId of desired) {
|
|
2981
|
+
if (!mounted.has(memoryStoreId)) await this.forwardClient.post(path, { memory_store_id: memoryStoreId });
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
async reconcileDefaultMemoryStore(identityId, templateId, desired) {
|
|
2985
|
+
const storeId = await this.findDefaultMemoryStoreId(identityId, templateId);
|
|
2986
|
+
if (!storeId) return { status: "pending" };
|
|
2987
|
+
const current = await this.forwardClient.get(`/memory_stores/${storeId}`);
|
|
2988
|
+
const descriptionChanged = desired.description !== void 0 && current.description !== desired.description;
|
|
2989
|
+
if (current.name === desired.name && !descriptionChanged) {
|
|
2990
|
+
return { status: "unchanged", memory_store_id: storeId };
|
|
2991
|
+
}
|
|
2992
|
+
await this.forwardClient.post(`/memory_stores/${storeId}`, {
|
|
2993
|
+
name: desired.name,
|
|
2994
|
+
...desired.description !== void 0 ? { description: desired.description } : {}
|
|
2995
|
+
});
|
|
2996
|
+
return { status: "updated", memory_store_id: storeId };
|
|
2997
|
+
}
|
|
2998
|
+
async findDefaultMemoryStoreId(identityId, templateId) {
|
|
2999
|
+
const mounts = await this.forwardClient.get(
|
|
3000
|
+
`/identities/${identityId}/templates/${templateId}/memory_stores`
|
|
3001
|
+
);
|
|
3002
|
+
const writableDefault = (mounts.data ?? []).find(
|
|
3003
|
+
(mount) => mount.system_managed === true && mount.access === "read_write"
|
|
3004
|
+
);
|
|
3005
|
+
return typeof writableDefault?.memory_store_id === "string" ? writableDefault.memory_store_id : null;
|
|
3006
|
+
}
|
|
3007
|
+
async deleteDefaultMemoryStore(id) {
|
|
3008
|
+
await this.client.delete(`/memory_stores/${id}`);
|
|
3009
|
+
}
|
|
2894
3010
|
async createIdentity(name, decl) {
|
|
2895
3011
|
if (decl.identity_id) return { id: decl.identity_id, type: "identity" };
|
|
2896
3012
|
const res = await this.forwardClient.post("/identities", {
|
|
@@ -2927,12 +3043,14 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2927
3043
|
}
|
|
2928
3044
|
async updateChannel(id, name, decl, refs) {
|
|
2929
3045
|
const current = await this.forwardClient.get(`/channels/${id}`);
|
|
2930
|
-
|
|
3046
|
+
const currentMode = current.identity_resolution?.mode ?? "fixed";
|
|
3047
|
+
if (current.channel_type !== decl.type || currentMode !== (decl.mode ?? "fixed")) {
|
|
2931
3048
|
await this.deleteChannel(id);
|
|
2932
3049
|
return this.createChannel(name, decl, refs);
|
|
2933
3050
|
}
|
|
2934
3051
|
const body = this.mapChannel(name, decl, refs);
|
|
2935
3052
|
delete body.channel_type;
|
|
3053
|
+
delete body.identity_resolution;
|
|
2936
3054
|
const res = await this.forwardClient.post(`/channels/${id}`, body);
|
|
2937
3055
|
return toRemoteResource(res);
|
|
2938
3056
|
}
|
|
@@ -2940,9 +3058,8 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2940
3058
|
await this.forwardClient.delete(`/channels/${id}`);
|
|
2941
3059
|
}
|
|
2942
3060
|
mapChannel(name, decl, refs) {
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
template_id: refs.agent_id,
|
|
3061
|
+
const mode = decl.mode ?? "fixed";
|
|
3062
|
+
const body = {
|
|
2946
3063
|
channel_type: decl.type,
|
|
2947
3064
|
name: decl.name ?? name,
|
|
2948
3065
|
enabled: decl.enabled ?? true,
|
|
@@ -2955,22 +3072,27 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2955
3072
|
}
|
|
2956
3073
|
}
|
|
2957
3074
|
};
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
resource: { id }
|
|
2964
|
-
});
|
|
3075
|
+
if (mode === "pairing") {
|
|
3076
|
+
body.identity_resolution = { mode: "pairing" };
|
|
3077
|
+
} else {
|
|
3078
|
+
body.identity_id = refs.identity_id;
|
|
3079
|
+
body.template_id = refs.agent_id;
|
|
2965
3080
|
}
|
|
3081
|
+
return body;
|
|
2966
3082
|
}
|
|
2967
|
-
async createMemoryStore(name, decl) {
|
|
3083
|
+
async createMemoryStore(name, decl, mode = "managed") {
|
|
2968
3084
|
const body = mapMemoryStore2(name, decl);
|
|
2969
|
-
const
|
|
3085
|
+
const client = mode === "forward" ? this.forwardClient : this.client;
|
|
3086
|
+
const memoryApi = mode === "forward" ? this.forwardMemoryApi : this.memoryApi;
|
|
3087
|
+
const res = await client.post(
|
|
3088
|
+
"/memory_stores",
|
|
3089
|
+
body,
|
|
3090
|
+
mode === "forward" ? { headers: { "Idempotency-Key": crypto.randomUUID() } } : void 0
|
|
3091
|
+
);
|
|
2970
3092
|
const storeId = res.id;
|
|
2971
3093
|
try {
|
|
2972
3094
|
for (const entry of decl.entries ?? []) {
|
|
2973
|
-
await
|
|
3095
|
+
await memoryApi.createMemory(storeId, { content: entry.content, path: entry.key });
|
|
2974
3096
|
}
|
|
2975
3097
|
} catch (error) {
|
|
2976
3098
|
await this.client.delete(`/memory_stores/${storeId}`).catch(() => void 0);
|
|
@@ -2978,7 +3100,7 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2978
3100
|
}
|
|
2979
3101
|
return toRemoteResource(res);
|
|
2980
3102
|
}
|
|
2981
|
-
async deleteMemoryStore(id) {
|
|
3103
|
+
async deleteMemoryStore(id, _mode = "managed") {
|
|
2982
3104
|
await this.client.delete(`/memory_stores/${id}`);
|
|
2983
3105
|
}
|
|
2984
3106
|
listMemoryStores(options) {
|
|
@@ -2987,23 +3109,23 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
2987
3109
|
getMemoryStore(id) {
|
|
2988
3110
|
return this.memoryApi.getStore(id);
|
|
2989
3111
|
}
|
|
2990
|
-
updateMemoryStore(id, input) {
|
|
2991
|
-
return this.memoryApi.updateStore(id, input);
|
|
3112
|
+
updateMemoryStore(id, input, mode = "managed") {
|
|
3113
|
+
return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).updateStore(id, input);
|
|
2992
3114
|
}
|
|
2993
3115
|
archiveMemoryStore(id) {
|
|
2994
3116
|
return this.memoryApi.archiveStore(id);
|
|
2995
3117
|
}
|
|
2996
|
-
createMemory(storeId, input) {
|
|
2997
|
-
return this.memoryApi.createMemory(storeId, input);
|
|
3118
|
+
createMemory(storeId, input, mode = "managed") {
|
|
3119
|
+
return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).createMemory(storeId, input);
|
|
2998
3120
|
}
|
|
2999
|
-
listMemories(storeId, options) {
|
|
3000
|
-
return this.memoryApi.listMemories(storeId, options);
|
|
3121
|
+
listMemories(storeId, options, mode = "managed") {
|
|
3122
|
+
return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).listMemories(storeId, options);
|
|
3001
3123
|
}
|
|
3002
3124
|
getMemory(storeId, memoryId) {
|
|
3003
3125
|
return this.memoryApi.getMemory(storeId, memoryId);
|
|
3004
3126
|
}
|
|
3005
|
-
updateMemory(storeId, memoryId, input) {
|
|
3006
|
-
return this.memoryApi.updateMemory(storeId, memoryId, input);
|
|
3127
|
+
updateMemory(storeId, memoryId, input, mode = "managed") {
|
|
3128
|
+
return (mode === "forward" ? this.forwardMemoryApi : this.memoryApi).updateMemory(storeId, memoryId, input);
|
|
3007
3129
|
}
|
|
3008
3130
|
deleteMemory(storeId, memoryId, expected) {
|
|
3009
3131
|
return this.memoryApi.deleteMemory(storeId, memoryId, expected);
|
|
@@ -3292,30 +3414,42 @@ var QoderAdapter = class _QoderAdapter {
|
|
|
3292
3414
|
return res.data;
|
|
3293
3415
|
}
|
|
3294
3416
|
// --- Files ---
|
|
3295
|
-
async uploadFile(filePath, options) {
|
|
3417
|
+
async uploadFile(filePath, options, mode = "managed") {
|
|
3418
|
+
if (mode === "forward" && options?.purpose && !["user_upload", "session_resource"].includes(options.purpose)) {
|
|
3419
|
+
throw new UserError(
|
|
3420
|
+
`Qoder Forward File purpose must be 'user_upload' or 'session_resource', got '${options.purpose}'.`
|
|
3421
|
+
);
|
|
3422
|
+
}
|
|
3296
3423
|
const resolved = resolve2(filePath);
|
|
3297
3424
|
const content = readFileSync2(resolved);
|
|
3298
3425
|
const fileName = options?.name ?? basename2(resolved);
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3426
|
+
const formData = buildFileFormData(new Uint8Array(content), fileName, { purpose: options?.purpose });
|
|
3427
|
+
const res = await (mode === "forward" ? this.forwardClient : this.client).postFormData(
|
|
3428
|
+
"/files",
|
|
3429
|
+
formData
|
|
3430
|
+
);
|
|
3431
|
+
return toRestFileInfo(res);
|
|
3302
3432
|
}
|
|
3303
3433
|
async uploadFileContent(content, filename, options) {
|
|
3304
|
-
const formData =
|
|
3305
|
-
const bytes = new Uint8Array(content);
|
|
3306
|
-
formData.append(
|
|
3307
|
-
"file",
|
|
3308
|
-
options?.mimeType ? new File([bytes], filename, { type: options.mimeType }) : new File([bytes], filename)
|
|
3309
|
-
);
|
|
3310
|
-
if (filename) formData.append("name", filename);
|
|
3311
|
-
if (options?.purpose) formData.append("purpose", options.purpose);
|
|
3434
|
+
const formData = buildFileFormData(content, filename, options);
|
|
3312
3435
|
const res = await this.client.postFormData("/files", formData);
|
|
3313
3436
|
return toRestFileInfo(res);
|
|
3314
3437
|
}
|
|
3315
|
-
async deleteFile(id) {
|
|
3316
|
-
await this.client.delete(`/files/${id}`);
|
|
3438
|
+
async deleteFile(id, mode = "managed") {
|
|
3439
|
+
await (mode === "forward" ? this.forwardClient : this.client).delete(`/files/${id}`);
|
|
3317
3440
|
}
|
|
3318
3441
|
};
|
|
3442
|
+
function buildFileFormData(content, filename, options) {
|
|
3443
|
+
const formData = new FormData();
|
|
3444
|
+
const bytes = new Uint8Array(content);
|
|
3445
|
+
formData.append(
|
|
3446
|
+
"file",
|
|
3447
|
+
options?.mimeType ? new File([bytes], filename, { type: options.mimeType }) : new File([bytes], filename)
|
|
3448
|
+
);
|
|
3449
|
+
if (filename) formData.append("name", filename);
|
|
3450
|
+
if (options?.purpose) formData.append("purpose", options.purpose);
|
|
3451
|
+
return formData;
|
|
3452
|
+
}
|
|
3319
3453
|
function toSessionInfo2(res) {
|
|
3320
3454
|
return buildSessionInfo(res, (r) => r.memory_store_ids ?? []);
|
|
3321
3455
|
}
|
|
@@ -3365,22 +3499,24 @@ function normalizeQoderMcpServers(value) {
|
|
|
3365
3499
|
});
|
|
3366
3500
|
});
|
|
3367
3501
|
}
|
|
3368
|
-
async function buildSkillFormData(name, decl, files) {
|
|
3502
|
+
async function buildSkillFormData(name, decl, files, fileField = "file", includeCreateFields = true, prefixTopLevelDirectory = false) {
|
|
3369
3503
|
const zip = new JSZip2();
|
|
3370
3504
|
for (const f of files) {
|
|
3371
|
-
zip.file(f.relativePath, f.content);
|
|
3505
|
+
zip.file(prefixTopLevelDirectory ? `${name}/${f.relativePath}` : f.relativePath, f.content);
|
|
3372
3506
|
}
|
|
3373
3507
|
const zipContent = await zip.generateAsync({ type: "uint8array" });
|
|
3374
3508
|
const formData = new FormData();
|
|
3375
3509
|
formData.append(
|
|
3376
|
-
|
|
3510
|
+
fileField,
|
|
3377
3511
|
new File([new Uint8Array(zipContent)], `${name}.zip`, {
|
|
3378
3512
|
type: "application/zip"
|
|
3379
3513
|
})
|
|
3380
3514
|
);
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3515
|
+
if (includeCreateFields) {
|
|
3516
|
+
formData.append("name", name);
|
|
3517
|
+
formData.append("type", "custom");
|
|
3518
|
+
if (decl.description) formData.append("description", decl.description);
|
|
3519
|
+
}
|
|
3384
3520
|
return formData;
|
|
3385
3521
|
}
|
|
3386
3522
|
|
|
@@ -4057,7 +4193,7 @@ var BailianAdapter = class _BailianAdapter {
|
|
|
4057
4193
|
}
|
|
4058
4194
|
async waitForFileReady(fileId) {
|
|
4059
4195
|
const start = Date.now();
|
|
4060
|
-
let
|
|
4196
|
+
let delay3 = FILE_SCAN_BACKOFF.initial;
|
|
4061
4197
|
let logged = false;
|
|
4062
4198
|
while (true) {
|
|
4063
4199
|
const detail = await this.client.get(`/files/${fileId}`);
|
|
@@ -4076,8 +4212,8 @@ var BailianAdapter = class _BailianAdapter {
|
|
|
4076
4212
|
);
|
|
4077
4213
|
return;
|
|
4078
4214
|
}
|
|
4079
|
-
await new Promise((r) => setTimeout(r,
|
|
4080
|
-
|
|
4215
|
+
await new Promise((r) => setTimeout(r, delay3));
|
|
4216
|
+
delay3 = Math.min(delay3 * FILE_SCAN_BACKOFF.factor, FILE_SCAN_BACKOFF.max);
|
|
4081
4217
|
}
|
|
4082
4218
|
}
|
|
4083
4219
|
// --- Vault (Vaults API) ---
|
|
@@ -5556,6 +5692,9 @@ var agentSkillRefSchema = z5.object({
|
|
|
5556
5692
|
var agentDeliverySchema = z5.object({
|
|
5557
5693
|
type: z5.enum(["managed", "forward"])
|
|
5558
5694
|
});
|
|
5695
|
+
var managedToolConfigSchema = z5.object({
|
|
5696
|
+
enabled_tools: z5.array(z5.string().min(1))
|
|
5697
|
+
});
|
|
5559
5698
|
var sessionGithubRepoResourceSchema = z5.object({
|
|
5560
5699
|
type: z5.literal("github_repository"),
|
|
5561
5700
|
url: z5.string().url(),
|
|
@@ -5577,19 +5716,27 @@ var agentSchema = z5.object({
|
|
|
5577
5716
|
mcp_servers: z5.array(mcpServerSchema).optional(),
|
|
5578
5717
|
skills: z5.array(z5.union([z5.string(), agentSkillRefSchema])).optional(),
|
|
5579
5718
|
vault: z5.string().optional(),
|
|
5719
|
+
files: z5.array(z5.string()).optional(),
|
|
5580
5720
|
memory_stores: z5.array(z5.string()).optional(),
|
|
5721
|
+
default_memory_store: z5.object({
|
|
5722
|
+
name: z5.string().trim().min(1).max(255),
|
|
5723
|
+
description: z5.string().max(1024).optional(),
|
|
5724
|
+
delete_on_destroy: z5.boolean().optional().default(false)
|
|
5725
|
+
}).optional(),
|
|
5581
5726
|
resources: z5.array(sessionGithubRepoResourceSchema).optional(),
|
|
5582
5727
|
multiagent: multiagentSchema.optional(),
|
|
5583
5728
|
metadata: z5.record(z5.string(), z5.string()).optional(),
|
|
5584
5729
|
environment_variables: z5.record(z5.string().min(1), z5.string()).optional(),
|
|
5730
|
+
managed_tool_config: managedToolConfigSchema.optional(),
|
|
5585
5731
|
delivery: z5.record(z5.string(), agentDeliverySchema).optional()
|
|
5586
5732
|
});
|
|
5587
5733
|
var channelSchema = z5.object({
|
|
5588
5734
|
provider: z5.string().optional(),
|
|
5589
|
-
agent: z5.string().min(1),
|
|
5735
|
+
agent: z5.string().min(1).optional(),
|
|
5590
5736
|
identity: z5.string().min(1).optional(),
|
|
5591
5737
|
type: z5.string().min(1),
|
|
5592
5738
|
name: z5.string().trim().min(1).optional(),
|
|
5739
|
+
mode: z5.enum(["fixed", "pairing"]).optional().default("fixed"),
|
|
5593
5740
|
enabled: z5.boolean().optional(),
|
|
5594
5741
|
credentials: z5.record(z5.string(), coerceString).optional(),
|
|
5595
5742
|
options: z5.record(z5.string(), z5.unknown()).optional()
|
|
@@ -5828,15 +5975,24 @@ async function computeResourceHash(address, config, basePath, state) {
|
|
|
5828
5975
|
if (!decl) return "";
|
|
5829
5976
|
if (address.type === "skill") {
|
|
5830
5977
|
const skillDecl = decl;
|
|
5978
|
+
const apiMode = resolveQoderApiMode(address.type, address.name, address.provider, config);
|
|
5831
5979
|
if (basePath) {
|
|
5832
5980
|
const fileHash = computeSkillContentHash(skillDecl.source, basePath);
|
|
5833
|
-
return contentHash({ decl, fileHash });
|
|
5981
|
+
return contentHash({ decl, fileHash, apiMode });
|
|
5834
5982
|
}
|
|
5983
|
+
return contentHash({ decl, apiMode });
|
|
5984
|
+
}
|
|
5985
|
+
if (address.type === "environment" || address.type === "vault" || address.type === "memory_store") {
|
|
5986
|
+
return contentHash({ decl, apiMode: resolveQoderApiMode(address.type, address.name, address.provider, config) });
|
|
5835
5987
|
}
|
|
5836
5988
|
if (address.type === "file" && basePath) {
|
|
5837
5989
|
const fileDecl = decl;
|
|
5838
5990
|
const fileHash = computeLocalFileContentHash(fileDecl.source, basePath);
|
|
5839
|
-
return contentHash({
|
|
5991
|
+
return contentHash({
|
|
5992
|
+
decl,
|
|
5993
|
+
fileHash,
|
|
5994
|
+
apiMode: resolveQoderApiMode("file", address.name, address.provider, config)
|
|
5995
|
+
});
|
|
5840
5996
|
}
|
|
5841
5997
|
if (address.type === "deployment") {
|
|
5842
5998
|
const refs = resolveDeploymentReferenceIds(decl, config, address.provider, state);
|
|
@@ -5858,13 +6014,28 @@ async function computeResourceHash(address, config, basePath, state) {
|
|
|
5858
6014
|
}
|
|
5859
6015
|
return contentHash(decl);
|
|
5860
6016
|
}
|
|
6017
|
+
function resolveQoderApiMode(type, name, provider, config) {
|
|
6018
|
+
if (provider !== "qoder") return void 0;
|
|
6019
|
+
if (type === "environment" && config.environments?.[name]?.environment_id) return "auto";
|
|
6020
|
+
for (const agent of Object.values(config.agents ?? {})) {
|
|
6021
|
+
if (agent.provider && agent.provider !== provider) continue;
|
|
6022
|
+
const referenced = type === "environment" ? agent.environment === name : type === "skill" ? agent.skills?.some(
|
|
6023
|
+
(skill) => typeof skill === "string" ? skill === name : skill.type === "custom" && skill.skill_id === name
|
|
6024
|
+
) : type === "vault" ? agent.vault === name : type === "memory_store" ? agent.memory_stores?.includes(name) : agent.files?.includes(name);
|
|
6025
|
+
if (referenced && agent.delivery?.qoder?.type === "forward") return "forward";
|
|
6026
|
+
}
|
|
6027
|
+
return "managed";
|
|
6028
|
+
}
|
|
5861
6029
|
function computeReplacementFingerprint(address, config) {
|
|
5862
6030
|
if (address.type !== "channel") return void 0;
|
|
5863
6031
|
const decl = config.channels?.[address.name];
|
|
5864
6032
|
if (!decl) return void 0;
|
|
5865
|
-
return contentHash({ channel_type: decl.type, credentials: decl.credentials ?? {} });
|
|
6033
|
+
return contentHash({ channel_type: decl.type, mode: decl.mode ?? "fixed", credentials: decl.credentials ?? {} });
|
|
5866
6034
|
}
|
|
5867
6035
|
function resolveChannelReferenceIds(decl, config, provider, state) {
|
|
6036
|
+
if (decl.mode === "pairing" || !decl.agent) {
|
|
6037
|
+
return { mode: "pairing" };
|
|
6038
|
+
}
|
|
5868
6039
|
const agent = config.agents?.[decl.agent];
|
|
5869
6040
|
const agentType = agent?.delivery?.[provider]?.type === "forward" ? "template" : "agent";
|
|
5870
6041
|
const identity = decl.identity ?? config.defaults?.identity;
|
|
@@ -5887,7 +6058,14 @@ function resolveTemplateReferenceIds(decl, config, provider, state) {
|
|
|
5887
6058
|
environment_id: environment?.environment_id ?? (decl.environment ? state?.getResource({ type: "environment", name: decl.environment, provider })?.remote_id ?? void 0 : void 0),
|
|
5888
6059
|
tunnel_id: tunnel?.tunnel_id,
|
|
5889
6060
|
vault_ids: decl.vault ? [state?.getResource({ type: "vault", name: decl.vault, provider })?.remote_id ?? decl.vault] : [],
|
|
5890
|
-
skill_ids: skillIds
|
|
6061
|
+
skill_ids: skillIds,
|
|
6062
|
+
memory_store_ids: (decl.memory_stores ?? []).map(
|
|
6063
|
+
(memoryStore) => state?.getResource({ type: "memory_store", name: memoryStore, provider })?.remote_id ?? memoryStore
|
|
6064
|
+
),
|
|
6065
|
+
file_ids: (decl.files ?? []).map(
|
|
6066
|
+
(file) => state?.getResource({ type: "file", name: file, provider })?.remote_id ?? file
|
|
6067
|
+
),
|
|
6068
|
+
identity_id: decl.memory_stores?.length && config.defaults?.identity ? state?.getResource({ type: "identity", name: config.defaults.identity, provider })?.remote_id : void 0
|
|
5891
6069
|
};
|
|
5892
6070
|
}
|
|
5893
6071
|
function resolveDeploymentReferenceIds(decl, config, provider, state) {
|
|
@@ -6067,11 +6245,21 @@ function resolveTemplateRefs(agentName, config, provider, state) {
|
|
|
6067
6245
|
const environment = config.environments?.[agent.environment];
|
|
6068
6246
|
if (!environment) throw new UserError(`Environment '${agent.environment}' is not defined in config.`);
|
|
6069
6247
|
const agentRefs = resolveAgentRefs(agentName, config, provider, state);
|
|
6248
|
+
const memoryStoreIds = (agent.memory_stores ?? []).map(
|
|
6249
|
+
(memoryStore) => requireRef(state, { type: "memory_store", name: memoryStore, provider })
|
|
6250
|
+
);
|
|
6251
|
+
const identityName = config.defaults?.identity;
|
|
6070
6252
|
return {
|
|
6071
6253
|
...agentRefs,
|
|
6072
6254
|
environment_id: environment.environment_id ?? requireRef(state, { type: "environment", name: agent.environment, provider }),
|
|
6073
6255
|
...agent.tunnel ? { tunnel_id: resolveTunnelIdFromConfig(config, agent.tunnel, provider) } : {},
|
|
6074
|
-
vault_ids: agent.vault ? [requireRef(state, { type: "vault", name: agent.vault, provider })] : []
|
|
6256
|
+
vault_ids: agent.vault ? [requireRef(state, { type: "vault", name: agent.vault, provider })] : [],
|
|
6257
|
+
file_ids: (agent.files ?? []).map((file) => requireRef(state, { type: "file", name: file, provider })),
|
|
6258
|
+
memory_store_ids: memoryStoreIds,
|
|
6259
|
+
owned_memory_store_ids: state.listResources().filter(
|
|
6260
|
+
(resource) => resource.address.provider === provider && resource.address.type === "memory_store" && resource.api_mode === "forward" && typeof resource.remote_id === "string"
|
|
6261
|
+
).map((resource) => resource.remote_id),
|
|
6262
|
+
...identityName ? { identity_id: requireRef(state, { type: "identity", name: identityName, provider }) } : {}
|
|
6075
6263
|
};
|
|
6076
6264
|
}
|
|
6077
6265
|
function resolveDeploymentRefs(deploymentName, config, provider, state) {
|
|
@@ -6133,6 +6321,12 @@ function resolveDeploymentRefs(deploymentName, config, provider, state) {
|
|
|
6133
6321
|
function resolveChannelRefs(channelName, config, provider, state) {
|
|
6134
6322
|
const channel = config.channels?.[channelName];
|
|
6135
6323
|
if (!channel) throw new UserError(`Channel '${channelName}' not found in config`);
|
|
6324
|
+
if (channel.mode === "pairing") {
|
|
6325
|
+
return {};
|
|
6326
|
+
}
|
|
6327
|
+
if (!channel.agent) {
|
|
6328
|
+
throw new UserError(`Channel '${channelName}' is fixed mode and must declare agent`);
|
|
6329
|
+
}
|
|
6136
6330
|
const agent = config.agents?.[channel.agent];
|
|
6137
6331
|
if (!agent) throw new UserError(`Channel '${channelName}' references unknown agent '${channel.agent}'`);
|
|
6138
6332
|
const agentType = agent.delivery?.[provider]?.type === "forward" ? "template" : "agent";
|
|
@@ -6255,6 +6449,7 @@ async function executePlan(plan, ctx, options = {}) {
|
|
|
6255
6449
|
await runWithConcurrency(level, concurrency, runAction);
|
|
6256
6450
|
await ctx.state.save();
|
|
6257
6451
|
}
|
|
6452
|
+
await reconcileDefaultMemoryStores(ctx, new Set(plan.actions.map((action) => action.address.provider)));
|
|
6258
6453
|
for (const action of deletions) {
|
|
6259
6454
|
await runAction(action);
|
|
6260
6455
|
await ctx.state.save();
|
|
@@ -6265,6 +6460,41 @@ async function executePlan(plan, ctx, options = {}) {
|
|
|
6265
6460
|
partial: results.some((r) => r.status === "failed")
|
|
6266
6461
|
};
|
|
6267
6462
|
}
|
|
6463
|
+
async function reconcileDefaultMemoryStores(ctx, plannedProviders) {
|
|
6464
|
+
const identityName = ctx.config.defaults?.identity;
|
|
6465
|
+
for (const [agentName, agent] of Object.entries(ctx.config.agents ?? {})) {
|
|
6466
|
+
const desired = agent.default_memory_store;
|
|
6467
|
+
if (!desired || agent.delivery?.qoder?.type !== "forward") continue;
|
|
6468
|
+
const providerName = "qoder";
|
|
6469
|
+
if (agent.provider && agent.provider !== providerName || !plannedProviders.has(providerName)) continue;
|
|
6470
|
+
const provider = ctx.providers.get(providerName);
|
|
6471
|
+
if (!provider?.reconcileDefaultMemoryStore || !identityName) continue;
|
|
6472
|
+
const identityId = ctx.state.getResource({
|
|
6473
|
+
type: "identity",
|
|
6474
|
+
name: identityName,
|
|
6475
|
+
provider: providerName
|
|
6476
|
+
})?.remote_id;
|
|
6477
|
+
const templateId = ctx.state.getResource({ type: "template", name: agentName, provider: providerName })?.remote_id;
|
|
6478
|
+
if (!identityId || !templateId) continue;
|
|
6479
|
+
const result = await provider.reconcileDefaultMemoryStore(identityId, templateId, desired);
|
|
6480
|
+
const resource = { type: "template", name: agentName, provider: providerName };
|
|
6481
|
+
if (result.status === "pending") {
|
|
6482
|
+
emitRuntimeFeedback(ctx.onFeedback, {
|
|
6483
|
+
type: "provider_wait",
|
|
6484
|
+
level: "warning",
|
|
6485
|
+
resource,
|
|
6486
|
+
message: `default memory store for template.${agentName} is pending \u2014 create the first Forward Session, then run apply again`
|
|
6487
|
+
});
|
|
6488
|
+
} else if (result.status === "updated") {
|
|
6489
|
+
emitRuntimeFeedback(ctx.onFeedback, {
|
|
6490
|
+
type: "resource_action_success",
|
|
6491
|
+
level: "success",
|
|
6492
|
+
resource,
|
|
6493
|
+
message: `updated default memory store for template.${agentName} to "${desired.name}"`
|
|
6494
|
+
});
|
|
6495
|
+
}
|
|
6496
|
+
}
|
|
6497
|
+
}
|
|
6268
6498
|
async function runWithConcurrency(items, limit, worker) {
|
|
6269
6499
|
if (items.length === 0) return;
|
|
6270
6500
|
let cursor = 0;
|
|
@@ -6343,6 +6573,7 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6343
6573
|
const existing = ctx.state.getResource(address);
|
|
6344
6574
|
if (!existing) return false;
|
|
6345
6575
|
const id = existing.remote_id;
|
|
6576
|
+
const apiMode2 = existing.api_mode;
|
|
6346
6577
|
if (type === "environment" || type === "identity") {
|
|
6347
6578
|
const externalReference = type === "environment" ? ctx.config.environments?.[name]?.environment_id : ctx.config.identities?.[name]?.identity_id;
|
|
6348
6579
|
if (existing.externally_managed || externalReference) {
|
|
@@ -6354,13 +6585,13 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6354
6585
|
try {
|
|
6355
6586
|
switch (type) {
|
|
6356
6587
|
case "environment":
|
|
6357
|
-
await provider.deleteEnvironment(id);
|
|
6588
|
+
await provider.deleteEnvironment(id, false, apiMode2);
|
|
6358
6589
|
break;
|
|
6359
6590
|
case "vault":
|
|
6360
|
-
await provider.deleteVault(id);
|
|
6591
|
+
await provider.deleteVault(id, apiMode2);
|
|
6361
6592
|
break;
|
|
6362
6593
|
case "skill":
|
|
6363
|
-
await provider.deleteSkill(id);
|
|
6594
|
+
await provider.deleteSkill(id, apiMode2);
|
|
6364
6595
|
break;
|
|
6365
6596
|
case "agent":
|
|
6366
6597
|
await provider.deleteAgent(id);
|
|
@@ -6368,17 +6599,17 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6368
6599
|
case "template":
|
|
6369
6600
|
if (!provider.archiveTemplate)
|
|
6370
6601
|
throw new UserError(`Provider '${address.provider}' does not support templates`);
|
|
6371
|
-
await provider.archiveTemplate(id);
|
|
6602
|
+
await provider.archiveTemplate(id, ownedForwardMemoryStoreIds(ctx, address.provider));
|
|
6372
6603
|
break;
|
|
6373
6604
|
case "memory_store":
|
|
6374
6605
|
if (!provider.deleteMemoryStore) throw memoryStoreUnsupported(address.provider);
|
|
6375
|
-
await provider.deleteMemoryStore(id);
|
|
6606
|
+
await provider.deleteMemoryStore(id, apiMode2);
|
|
6376
6607
|
break;
|
|
6377
6608
|
case "deployment":
|
|
6378
6609
|
await provider.deleteDeployment(id);
|
|
6379
6610
|
break;
|
|
6380
6611
|
case "file":
|
|
6381
|
-
await provider.deleteFile(id);
|
|
6612
|
+
await provider.deleteFile(id, apiMode2);
|
|
6382
6613
|
break;
|
|
6383
6614
|
case "identity":
|
|
6384
6615
|
if (!provider.deleteIdentity)
|
|
@@ -6407,6 +6638,9 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6407
6638
|
const isUpdate = action.action === "update";
|
|
6408
6639
|
const priorAddress = action.previousAddress ?? address;
|
|
6409
6640
|
const existingId = isUpdate ? ctx.state.getResource(priorAddress)?.remote_id : void 0;
|
|
6641
|
+
const apiMode = resolveResourceApiMode(type, name, address.provider, ctx.config);
|
|
6642
|
+
const priorApiMode = ctx.state.getResource(priorAddress)?.api_mode ?? (address.provider === "qoder" ? "managed" : void 0);
|
|
6643
|
+
const apiModeChanged = isUpdate && apiMode !== void 0 && priorApiMode !== apiMode;
|
|
6410
6644
|
let result;
|
|
6411
6645
|
switch (type) {
|
|
6412
6646
|
case "environment": {
|
|
@@ -6421,6 +6655,17 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6421
6655
|
resource: action.address,
|
|
6422
6656
|
message: `${action.action} ${action.address.type}.${action.address.name} (${action.address.provider}) \u2014 external reference, no remote mutation`
|
|
6423
6657
|
});
|
|
6658
|
+
} else if (apiModeChanged) {
|
|
6659
|
+
try {
|
|
6660
|
+
result = await provider.createEnvironment(remoteName, decl, apiMode);
|
|
6661
|
+
} catch (err) {
|
|
6662
|
+
result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
|
|
6663
|
+
mode: apiMode,
|
|
6664
|
+
onExisting: (existing) => provider.updateEnvironment(existing.id, remoteName, decl, apiMode)
|
|
6665
|
+
});
|
|
6666
|
+
adopted = true;
|
|
6667
|
+
}
|
|
6668
|
+
if (existingId) await provider.deleteEnvironment(existingId, false, priorApiMode);
|
|
6424
6669
|
} else if (isUpdate) {
|
|
6425
6670
|
const prior = ctx.state.getResource(address);
|
|
6426
6671
|
if (prior?.externally_managed) {
|
|
@@ -6428,13 +6673,14 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6428
6673
|
`environment.${name} is recorded as an external reference (${prior.remote_id ?? "unknown id"}); refusing to modify it remotely. Restore 'environment_id' to keep it as a reference, or release it first with 'agents state rm environment.${name}' (then 'agents state import' to adopt it as a managed resource).`
|
|
6429
6674
|
);
|
|
6430
6675
|
}
|
|
6431
|
-
result = await provider.updateEnvironment(existingId, remoteName, decl);
|
|
6676
|
+
result = await provider.updateEnvironment(existingId, remoteName, decl, apiMode);
|
|
6432
6677
|
} else {
|
|
6433
6678
|
try {
|
|
6434
|
-
result = await provider.createEnvironment(remoteName, decl);
|
|
6679
|
+
result = await provider.createEnvironment(remoteName, decl, apiMode);
|
|
6435
6680
|
} catch (err) {
|
|
6436
6681
|
result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
|
|
6437
|
-
|
|
6682
|
+
mode: apiMode,
|
|
6683
|
+
onExisting: (existing) => provider.updateEnvironment(existing.id, remoteName, decl, apiMode)
|
|
6438
6684
|
});
|
|
6439
6685
|
adopted = true;
|
|
6440
6686
|
}
|
|
@@ -6443,22 +6689,26 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6443
6689
|
}
|
|
6444
6690
|
case "vault": {
|
|
6445
6691
|
const decl = ctx.config.vaults[name];
|
|
6446
|
-
if (
|
|
6692
|
+
if (apiModeChanged) {
|
|
6693
|
+
result = await provider.createVault(name, decl, apiMode);
|
|
6694
|
+
if (existingId) await provider.deleteVault(existingId, priorApiMode).catch(() => void 0);
|
|
6695
|
+
} else if (isUpdate) {
|
|
6447
6696
|
try {
|
|
6448
|
-
result = await provider.createVault(name, decl);
|
|
6449
|
-
await provider.deleteVault(existingId);
|
|
6697
|
+
result = await provider.createVault(name, decl, apiMode);
|
|
6698
|
+
await provider.deleteVault(existingId, apiMode);
|
|
6450
6699
|
} catch {
|
|
6451
|
-
await provider.deleteVault(existingId);
|
|
6452
|
-
result = await provider.createVault(name, decl);
|
|
6700
|
+
await provider.deleteVault(existingId, apiMode);
|
|
6701
|
+
result = await provider.createVault(name, decl, apiMode);
|
|
6453
6702
|
}
|
|
6454
6703
|
} else {
|
|
6455
6704
|
try {
|
|
6456
|
-
result = await provider.createVault(name, decl);
|
|
6705
|
+
result = await provider.createVault(name, decl, apiMode);
|
|
6457
6706
|
} catch (err) {
|
|
6458
6707
|
result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
|
|
6708
|
+
mode: apiMode,
|
|
6459
6709
|
onExisting: async (existing) => {
|
|
6460
|
-
await provider.deleteVault(existing.id);
|
|
6461
|
-
return provider.createVault(name, decl);
|
|
6710
|
+
await provider.deleteVault(existing.id, apiMode);
|
|
6711
|
+
return provider.createVault(name, decl, apiMode);
|
|
6462
6712
|
}
|
|
6463
6713
|
});
|
|
6464
6714
|
adopted = true;
|
|
@@ -6482,12 +6732,15 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6482
6732
|
}
|
|
6483
6733
|
const remoteName = decl.name ?? name;
|
|
6484
6734
|
const files = await resolveSkillFiles(decl, ctx);
|
|
6485
|
-
if (
|
|
6486
|
-
result = await provider.
|
|
6735
|
+
if (apiModeChanged) {
|
|
6736
|
+
result = await provider.createSkill(remoteName, decl, files, apiMode);
|
|
6737
|
+
if (existingId) await provider.deleteSkill(existingId, priorApiMode).catch(() => void 0);
|
|
6738
|
+
} else if (isUpdate) {
|
|
6739
|
+
result = await provider.updateSkill(existingId, remoteName, decl, files, apiMode);
|
|
6487
6740
|
} else {
|
|
6488
6741
|
const manifestName = skillNameFromFiles(files);
|
|
6489
6742
|
const searchNames = manifestName && manifestName !== remoteName ? [remoteName, manifestName] : [remoteName];
|
|
6490
|
-
const existing = await findExistingByNames(provider, "skill", searchNames);
|
|
6743
|
+
const existing = await findExistingByNames(provider, "skill", searchNames, apiMode);
|
|
6491
6744
|
if (existing) {
|
|
6492
6745
|
result = existing.resource;
|
|
6493
6746
|
emitRuntimeFeedback(ctx.onFeedback, {
|
|
@@ -6499,9 +6752,10 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6499
6752
|
adopted = true;
|
|
6500
6753
|
} else {
|
|
6501
6754
|
try {
|
|
6502
|
-
result = await provider.createSkill(remoteName, decl, files);
|
|
6755
|
+
result = await provider.createSkill(remoteName, decl, files, apiMode);
|
|
6503
6756
|
} catch (err) {
|
|
6504
6757
|
result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
|
|
6758
|
+
mode: apiMode,
|
|
6505
6759
|
searchNames,
|
|
6506
6760
|
onExisting: async (existing2) => existing2
|
|
6507
6761
|
});
|
|
@@ -6520,15 +6774,19 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6520
6774
|
throw memoryStoreUnsupported(address.provider);
|
|
6521
6775
|
}
|
|
6522
6776
|
const reconcile = async (storeId) => {
|
|
6523
|
-
const store = await provider.updateMemoryStore(
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6777
|
+
const store = await provider.updateMemoryStore(
|
|
6778
|
+
storeId,
|
|
6779
|
+
{
|
|
6780
|
+
name,
|
|
6781
|
+
description: decl.description,
|
|
6782
|
+
metadata: decl.metadata ?? {}
|
|
6783
|
+
},
|
|
6784
|
+
apiMode
|
|
6785
|
+
);
|
|
6528
6786
|
const current = /* @__PURE__ */ new Map();
|
|
6529
6787
|
let cursor;
|
|
6530
6788
|
do {
|
|
6531
|
-
const page2 = await provider.listMemories(storeId, { limit: 100, cursor, view: "basic" });
|
|
6789
|
+
const page2 = await provider.listMemories(storeId, { limit: 100, cursor, view: "basic" }, apiMode);
|
|
6532
6790
|
for (const memory of page2.data) {
|
|
6533
6791
|
if (memory.type === "memory") current.set(memory.path, memory);
|
|
6534
6792
|
}
|
|
@@ -6538,24 +6796,33 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6538
6796
|
const existing = current.get(entry.key.replace(/^\/+/, ""));
|
|
6539
6797
|
if (existing) {
|
|
6540
6798
|
if (existing.content_sha256 !== sha256(entry.content)) {
|
|
6541
|
-
await provider.updateMemory(
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6799
|
+
await provider.updateMemory(
|
|
6800
|
+
storeId,
|
|
6801
|
+
existing.id,
|
|
6802
|
+
{
|
|
6803
|
+
content: entry.content,
|
|
6804
|
+
expected_content_sha256: existing.content_sha256
|
|
6805
|
+
},
|
|
6806
|
+
apiMode
|
|
6807
|
+
);
|
|
6545
6808
|
}
|
|
6546
6809
|
} else {
|
|
6547
|
-
await provider.createMemory(storeId, { path: entry.key, content: entry.content });
|
|
6810
|
+
await provider.createMemory(storeId, { path: entry.key, content: entry.content }, apiMode);
|
|
6548
6811
|
}
|
|
6549
6812
|
}
|
|
6550
6813
|
return store;
|
|
6551
6814
|
};
|
|
6552
|
-
if (
|
|
6815
|
+
if (apiModeChanged) {
|
|
6816
|
+
result = await createMemoryStore2(name, decl, apiMode);
|
|
6817
|
+
if (existingId) await deleteMemoryStore2(existingId, priorApiMode).catch(() => void 0);
|
|
6818
|
+
} else if (isUpdate) {
|
|
6553
6819
|
result = await reconcile(existingId);
|
|
6554
6820
|
} else {
|
|
6555
6821
|
try {
|
|
6556
|
-
result = await createMemoryStore2(name, decl);
|
|
6822
|
+
result = await createMemoryStore2(name, decl, apiMode);
|
|
6557
6823
|
} catch (err) {
|
|
6558
6824
|
result = await adoptOnConflict(err, address, provider, ctx.onFeedback, {
|
|
6825
|
+
mode: apiMode,
|
|
6559
6826
|
onExisting: async (existing) => reconcile(existing.id)
|
|
6560
6827
|
});
|
|
6561
6828
|
adopted = true;
|
|
@@ -6705,15 +6972,12 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6705
6972
|
const oldId = ctx.state.getResource(address)?.remote_id;
|
|
6706
6973
|
if (oldId) {
|
|
6707
6974
|
try {
|
|
6708
|
-
await provider.deleteFile(oldId);
|
|
6975
|
+
await provider.deleteFile(oldId, priorApiMode);
|
|
6709
6976
|
} catch {
|
|
6710
6977
|
}
|
|
6711
6978
|
}
|
|
6712
6979
|
}
|
|
6713
|
-
const info = await provider.uploadFile(filePath, {
|
|
6714
|
-
name: decl.name,
|
|
6715
|
-
purpose: decl.purpose
|
|
6716
|
-
});
|
|
6980
|
+
const info = await provider.uploadFile(filePath, { name: decl.name, purpose: decl.purpose }, apiMode);
|
|
6717
6981
|
result = { id: info.id, type: "file" };
|
|
6718
6982
|
break;
|
|
6719
6983
|
}
|
|
@@ -6734,6 +6998,7 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6734
6998
|
address,
|
|
6735
6999
|
remote_id: result.id,
|
|
6736
7000
|
externally_managed: priorResource?.externally_managed || type === "environment" && ctx.config.environments?.[name]?.environment_id || type === "identity" && ctx.config.identities?.[name]?.identity_id ? true : void 0,
|
|
7001
|
+
api_mode: apiMode,
|
|
6737
7002
|
version: result.version,
|
|
6738
7003
|
content_hash: hash,
|
|
6739
7004
|
desired_hash: hash,
|
|
@@ -6748,9 +7013,37 @@ async function executeActionInner(action, provider, ctx) {
|
|
|
6748
7013
|
if (action.previousAddress) ctx.state.removeResource(action.previousAddress);
|
|
6749
7014
|
return adopted;
|
|
6750
7015
|
}
|
|
6751
|
-
|
|
7016
|
+
function ownedForwardMemoryStoreIds(ctx, provider) {
|
|
7017
|
+
return ctx.state.listResources().filter(
|
|
7018
|
+
(resource) => resource.address.provider === provider && resource.address.type === "memory_store" && resource.api_mode === "forward" && typeof resource.remote_id === "string"
|
|
7019
|
+
).map((resource) => resource.remote_id);
|
|
7020
|
+
}
|
|
7021
|
+
function resolveResourceApiMode(type, name, provider, config) {
|
|
7022
|
+
if (provider !== "qoder" || type !== "environment" && type !== "skill" && type !== "vault" && type !== "memory_store" && type !== "file") {
|
|
7023
|
+
return void 0;
|
|
7024
|
+
}
|
|
7025
|
+
if (type === "environment" && config.environments?.[name]?.environment_id) return "auto";
|
|
7026
|
+
let managed = false;
|
|
7027
|
+
let forward = false;
|
|
7028
|
+
for (const agent of Object.values(config.agents ?? {})) {
|
|
7029
|
+
if (agent.provider && agent.provider !== provider) continue;
|
|
7030
|
+
const referenced = type === "environment" ? agent.environment === name : type === "skill" ? agent.skills?.some(
|
|
7031
|
+
(skill) => typeof skill === "string" ? skill === name : skill.type === "custom" && skill.skill_id === name
|
|
7032
|
+
) : type === "vault" ? agent.vault === name : type === "memory_store" ? agent.memory_stores?.includes(name) : agent.files?.includes(name);
|
|
7033
|
+
if (!referenced) continue;
|
|
7034
|
+
if (agent.delivery?.qoder?.type === "forward") forward = true;
|
|
7035
|
+
else managed = true;
|
|
7036
|
+
}
|
|
7037
|
+
if (managed && forward) {
|
|
7038
|
+
throw new UserError(
|
|
7039
|
+
`Qoder ${type}.${name} is referenced by both Managed and Forward agents; declare separate resources for each API domain.`
|
|
7040
|
+
);
|
|
7041
|
+
}
|
|
7042
|
+
return forward ? "forward" : "managed";
|
|
7043
|
+
}
|
|
7044
|
+
async function findExistingByNames(provider, type, names, mode) {
|
|
6752
7045
|
for (const candidate of names) {
|
|
6753
|
-
const found = await provider.findResource(type, candidate);
|
|
7046
|
+
const found = await provider.findResource(type, candidate, void 0, mode);
|
|
6754
7047
|
if (found && found.id !== null) return { resource: found, name: candidate };
|
|
6755
7048
|
}
|
|
6756
7049
|
return null;
|
|
@@ -6758,7 +7051,7 @@ async function findExistingByNames(provider, type, names) {
|
|
|
6758
7051
|
async function adoptOnConflict(err, address, provider, onFeedback, opts) {
|
|
6759
7052
|
if (!(err instanceof ConflictError)) throw err;
|
|
6760
7053
|
const candidates = opts.searchNames?.length ? opts.searchNames : [address.name];
|
|
6761
|
-
const existing = await findExistingByNames(provider, address.type, candidates);
|
|
7054
|
+
const existing = await findExistingByNames(provider, address.type, candidates, opts.mode);
|
|
6762
7055
|
if (!existing) throw nameReservedError(err, address, candidates.join('" / "'));
|
|
6763
7056
|
emitRuntimeFeedback(onFeedback, {
|
|
6764
7057
|
type: "resource_adopted",
|
|
@@ -6847,6 +7140,13 @@ function agentTargetsProvider(config, agentProvider, providerName) {
|
|
|
6847
7140
|
return Object.hasOwn(config.providers, providerName);
|
|
6848
7141
|
}
|
|
6849
7142
|
|
|
7143
|
+
// src/internal/core/agent-materialization.ts
|
|
7144
|
+
function resolveAgentMaterialization(provider, agent) {
|
|
7145
|
+
const mode = agent.delivery?.[provider]?.type ?? "managed";
|
|
7146
|
+
if (mode === "managed") return { resourceType: "agent", mode };
|
|
7147
|
+
return { resourceType: "template", mode };
|
|
7148
|
+
}
|
|
7149
|
+
|
|
6850
7150
|
// src/internal/core/validate-config.ts
|
|
6851
7151
|
function validateProjectConfig(config, options = {}) {
|
|
6852
7152
|
const collector = new DiagnosticCollector();
|
|
@@ -6873,6 +7173,7 @@ function collectReferenceDiagnostics(config, diagnostics) {
|
|
|
6873
7173
|
const skillNames = new Set(Object.keys(config.skills ?? {}));
|
|
6874
7174
|
const vaultNames = new Set(Object.keys(config.vaults ?? {}));
|
|
6875
7175
|
const memoryNames = new Set(Object.keys(config.memory_stores ?? {}));
|
|
7176
|
+
const fileNames = new Set(Object.keys(config.files ?? {}));
|
|
6876
7177
|
const agentNames = new Set(Object.keys(config.agents ?? {}));
|
|
6877
7178
|
const identityNames = new Set(Object.keys(config.identities ?? {}));
|
|
6878
7179
|
if (config.defaults?.identity && !identityNames.has(config.defaults.identity)) {
|
|
@@ -6900,6 +7201,11 @@ function collectReferenceDiagnostics(config, diagnostics) {
|
|
|
6900
7201
|
if (agent.vault && !vaultNames.has(agent.vault)) {
|
|
6901
7202
|
diagnostics.error("config.agent.vault.unknown", `agent.${name}: references unknown vault '${agent.vault}'`);
|
|
6902
7203
|
}
|
|
7204
|
+
for (const file of agent.files ?? []) {
|
|
7205
|
+
if (!fileNames.has(file)) {
|
|
7206
|
+
diagnostics.error("config.agent.file.unknown", `agent.${name}: references unknown file '${file}'`);
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
6903
7209
|
for (const memory of agent.memory_stores ?? []) {
|
|
6904
7210
|
if (!memoryNames.has(memory)) {
|
|
6905
7211
|
diagnostics.error(
|
|
@@ -6931,7 +7237,10 @@ function collectReferenceDiagnostics(config, diagnostics) {
|
|
|
6931
7237
|
}
|
|
6932
7238
|
}
|
|
6933
7239
|
for (const [name, channel] of Object.entries(config.channels ?? {})) {
|
|
6934
|
-
if (
|
|
7240
|
+
if (channel.mode === "pairing") continue;
|
|
7241
|
+
if (!channel.agent) {
|
|
7242
|
+
diagnostics.error("config.channel.agent.required", `channel.${name}: fixed-mode channels require agent`);
|
|
7243
|
+
} else if (!agentNames.has(channel.agent)) {
|
|
6935
7244
|
diagnostics.error("config.channel.agent.unknown", `channel.${name}: references unknown agent '${channel.agent}'`);
|
|
6936
7245
|
}
|
|
6937
7246
|
const identity = channel.identity ?? config.defaults?.identity;
|
|
@@ -7011,29 +7320,31 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7011
7320
|
continue;
|
|
7012
7321
|
}
|
|
7013
7322
|
if (providerName === "qoder") {
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7323
|
+
if (channel.mode !== "pairing" && channel.agent) {
|
|
7324
|
+
const agent = config.agents?.[channel.agent];
|
|
7325
|
+
if (agent?.provider && agent.provider !== providerName) {
|
|
7326
|
+
diagnostics.error(
|
|
7327
|
+
"config.channel.agent.provider_mismatch",
|
|
7328
|
+
`channel.${name}: agent '${channel.agent}' is pinned to provider '${agent.provider}'.`,
|
|
7329
|
+
{ type: "channel", name, provider: providerName }
|
|
7330
|
+
);
|
|
7331
|
+
}
|
|
7332
|
+
const identityName = channel.identity ?? config.defaults?.identity;
|
|
7333
|
+
const identity = identityName ? config.identities?.[identityName] : void 0;
|
|
7334
|
+
if (identity?.provider && identity.provider !== providerName) {
|
|
7335
|
+
diagnostics.error(
|
|
7336
|
+
"config.channel.identity.provider_mismatch",
|
|
7337
|
+
`channel.${name}: identity '${identityName}' is pinned to provider '${identity.provider}'.`,
|
|
7338
|
+
{ type: "channel", name, provider: providerName }
|
|
7339
|
+
);
|
|
7340
|
+
}
|
|
7341
|
+
if (agent && agent.delivery?.qoder?.type !== "forward") {
|
|
7342
|
+
diagnostics.error(
|
|
7343
|
+
"qoder.channel.forward_template.required",
|
|
7344
|
+
`channel.${name}: Qoder Channels require agent '${channel.agent}' to use delivery.qoder.type: forward.`,
|
|
7345
|
+
{ type: "channel", name, provider: providerName }
|
|
7346
|
+
);
|
|
7347
|
+
}
|
|
7037
7348
|
}
|
|
7038
7349
|
const requiredCredentials = {
|
|
7039
7350
|
dingtalk: ["client_id", "client_secret"],
|
|
@@ -7064,6 +7375,46 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7064
7375
|
}
|
|
7065
7376
|
}
|
|
7066
7377
|
}
|
|
7378
|
+
if (providerName === "qoder") {
|
|
7379
|
+
const domains = /* @__PURE__ */ new Map();
|
|
7380
|
+
for (const agent of Object.values(config.agents ?? {})) {
|
|
7381
|
+
if (agent.provider && agent.provider !== providerName) continue;
|
|
7382
|
+
const mode = agent.delivery?.qoder?.type === "forward" ? "forward" : "managed";
|
|
7383
|
+
const refs = [
|
|
7384
|
+
...agent.environment && !config.environments?.[agent.environment]?.environment_id ? [`environment:${agent.environment}`] : [],
|
|
7385
|
+
...(agent.skills ?? []).flatMap(
|
|
7386
|
+
(skill) => typeof skill === "string" ? [`skill:${skill}`] : skill.type === "custom" ? [`skill:${skill.skill_id}`] : []
|
|
7387
|
+
),
|
|
7388
|
+
...agent.vault ? [`vault:${agent.vault}`] : [],
|
|
7389
|
+
...(agent.memory_stores ?? []).map((store) => `memory_store:${store}`),
|
|
7390
|
+
...(agent.files ?? []).map((file) => `file:${file}`)
|
|
7391
|
+
];
|
|
7392
|
+
for (const ref of refs) {
|
|
7393
|
+
const modes = domains.get(ref) ?? /* @__PURE__ */ new Set();
|
|
7394
|
+
modes.add(mode);
|
|
7395
|
+
domains.set(ref, modes);
|
|
7396
|
+
}
|
|
7397
|
+
}
|
|
7398
|
+
for (const [ref, modes] of domains) {
|
|
7399
|
+
if (modes.size < 2) continue;
|
|
7400
|
+
const [type, name] = ref.split(":");
|
|
7401
|
+
diagnostics.error(
|
|
7402
|
+
`qoder.${type}.delivery_domain.conflict`,
|
|
7403
|
+
`${type}.${name}: referenced by both Managed and Forward agents; declare separate resources because Qoder uses different API domains.`,
|
|
7404
|
+
{ type, name, provider: providerName }
|
|
7405
|
+
);
|
|
7406
|
+
}
|
|
7407
|
+
}
|
|
7408
|
+
for (const [name, agent] of Object.entries(config.agents ?? {})) {
|
|
7409
|
+
if (agent.provider && agent.provider !== providerName) continue;
|
|
7410
|
+
if (agent.files?.length && (providerName !== "qoder" || agent.delivery?.qoder?.type !== "forward")) {
|
|
7411
|
+
diagnostics.error(
|
|
7412
|
+
"config.agent.files.unsupported",
|
|
7413
|
+
`agent.${name}: files are supported only by Qoder Forward Templates.`,
|
|
7414
|
+
{ type: resolveAgentMaterialization(providerName, agent).resourceType, name, provider: providerName }
|
|
7415
|
+
);
|
|
7416
|
+
}
|
|
7417
|
+
}
|
|
7067
7418
|
for (const [name, agent] of Object.entries(config.agents ?? {})) {
|
|
7068
7419
|
if (agent.provider && agent.provider !== providerName) continue;
|
|
7069
7420
|
const delivery = agent.delivery?.[providerName]?.type ?? "managed";
|
|
@@ -7104,6 +7455,44 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7104
7455
|
address
|
|
7105
7456
|
);
|
|
7106
7457
|
}
|
|
7458
|
+
if (delivery !== "forward" && agent.managed_tool_config) {
|
|
7459
|
+
diagnostics.error(
|
|
7460
|
+
`${providerName}.agent.managed_tool_config.forward_required`,
|
|
7461
|
+
`agent.${name}: managed_tool_config applies to Forward Templates; set delivery.${providerName}.type: forward or remove it.`,
|
|
7462
|
+
address
|
|
7463
|
+
);
|
|
7464
|
+
}
|
|
7465
|
+
if (agent.default_memory_store) {
|
|
7466
|
+
if (providerName !== "qoder" || delivery !== "forward") {
|
|
7467
|
+
diagnostics.error(
|
|
7468
|
+
`${providerName}.agent.default_memory_store.forward_required`,
|
|
7469
|
+
`agent.${name}: default_memory_store is supported only by Qoder Forward delivery.`,
|
|
7470
|
+
address
|
|
7471
|
+
);
|
|
7472
|
+
} else if (!config.defaults?.identity) {
|
|
7473
|
+
diagnostics.error(
|
|
7474
|
+
"qoder.template.default_memory_store.identity.required",
|
|
7475
|
+
`agent.${name}: default_memory_store requires defaults.identity to select the owning Forward Identity.`,
|
|
7476
|
+
{ type: "template", name, provider: providerName }
|
|
7477
|
+
);
|
|
7478
|
+
} else {
|
|
7479
|
+
const identity = config.identities?.[config.defaults.identity];
|
|
7480
|
+
if (identity?.provider && identity.provider !== providerName) {
|
|
7481
|
+
diagnostics.error(
|
|
7482
|
+
"qoder.template.default_memory_store.identity.provider_mismatch",
|
|
7483
|
+
`agent.${name}: defaults.identity '${config.defaults.identity}' is pinned to provider '${identity.provider}'.`,
|
|
7484
|
+
{ type: "template", name, provider: providerName }
|
|
7485
|
+
);
|
|
7486
|
+
}
|
|
7487
|
+
if (agent.default_memory_store.delete_on_destroy && identity?.identity_id) {
|
|
7488
|
+
diagnostics.error(
|
|
7489
|
+
"qoder.template.default_memory_store.delete.external_identity",
|
|
7490
|
+
`agent.${name}: delete_on_destroy requires an OpenCMA-managed Identity because an external Identity keeps the default Memory Store mounted.`,
|
|
7491
|
+
{ type: "template", name, provider: providerName }
|
|
7492
|
+
);
|
|
7493
|
+
}
|
|
7494
|
+
}
|
|
7495
|
+
}
|
|
7107
7496
|
if (delivery === "forward" && !isSupported(caps, "template")) {
|
|
7108
7497
|
diagnostics.error(
|
|
7109
7498
|
`${providerName}.agent.delivery.forward.unsupported`,
|
|
@@ -7119,10 +7508,10 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7119
7508
|
{ type: "template", name, provider: providerName }
|
|
7120
7509
|
);
|
|
7121
7510
|
}
|
|
7122
|
-
if (agent.memory_stores?.length) {
|
|
7511
|
+
if (agent.memory_stores?.length && !config.defaults?.identity) {
|
|
7123
7512
|
diagnostics.error(
|
|
7124
|
-
"qoder.template.memory_store.
|
|
7125
|
-
`agent.${name}: memory_stores
|
|
7513
|
+
"qoder.template.memory_store.identity.required",
|
|
7514
|
+
`agent.${name}: Forward memory_stores require defaults.identity for the Identity/Template mount.`,
|
|
7126
7515
|
{ type: "template", name, provider: providerName }
|
|
7127
7516
|
);
|
|
7128
7517
|
}
|
|
@@ -7237,6 +7626,13 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7237
7626
|
{ type: "agent", name, provider: providerName }
|
|
7238
7627
|
);
|
|
7239
7628
|
}
|
|
7629
|
+
if (agent.managed_tool_config && (!agent.provider || agent.provider === providerName)) {
|
|
7630
|
+
diagnostics.error(
|
|
7631
|
+
`${providerName}.agent.managed_tool_config.unsupported`,
|
|
7632
|
+
`agent.${name}: managed_tool_config is supported only by Qoder; remove it or pin this agent to qoder.`,
|
|
7633
|
+
{ type: "agent", name, provider: providerName }
|
|
7634
|
+
);
|
|
7635
|
+
}
|
|
7240
7636
|
if (agent.tunnel && (!agent.provider || agent.provider === providerName)) {
|
|
7241
7637
|
diagnostics.error(
|
|
7242
7638
|
`${providerName}.agent.tunnel.unsupported`,
|
|
@@ -7335,13 +7731,6 @@ function collectProviderCapabilities(config, providers, diagnostics) {
|
|
|
7335
7731
|
}
|
|
7336
7732
|
}
|
|
7337
7733
|
|
|
7338
|
-
// src/internal/core/agent-materialization.ts
|
|
7339
|
-
function resolveAgentMaterialization(provider, agent) {
|
|
7340
|
-
const mode = agent.delivery?.[provider]?.type ?? "managed";
|
|
7341
|
-
if (mode === "managed") return { resourceType: "agent", mode };
|
|
7342
|
-
return { resourceType: "template", mode };
|
|
7343
|
-
}
|
|
7344
|
-
|
|
7345
7734
|
// src/internal/graph/dependency.ts
|
|
7346
7735
|
function buildDependencyGraph(config, targetProviders) {
|
|
7347
7736
|
const nodes = /* @__PURE__ */ new Map();
|
|
@@ -7409,6 +7798,13 @@ function buildDependencyGraph(config, targetProviders) {
|
|
|
7409
7798
|
const materialization = resolveAgentMaterialization(provider, decl);
|
|
7410
7799
|
const agentAddr = { type: materialization.resourceType, name, provider };
|
|
7411
7800
|
addNode(agentAddr);
|
|
7801
|
+
if ((decl.default_memory_store || decl.memory_stores?.length) && materialization.resourceType === "template") {
|
|
7802
|
+
const identityName = config.defaults?.identity;
|
|
7803
|
+
if (identityName) {
|
|
7804
|
+
const identityAddr = { type: "identity", name: identityName, provider };
|
|
7805
|
+
if (nodes.has(addressKey(identityAddr))) addEdge(agentAddr, identityAddr);
|
|
7806
|
+
}
|
|
7807
|
+
}
|
|
7412
7808
|
if (decl.environment && config.environments?.[decl.environment]) {
|
|
7413
7809
|
const envAddr = {
|
|
7414
7810
|
type: "environment",
|
|
@@ -7435,6 +7831,12 @@ function buildDependencyGraph(config, targetProviders) {
|
|
|
7435
7831
|
addEdge(agentAddr, vaultAddr);
|
|
7436
7832
|
}
|
|
7437
7833
|
}
|
|
7834
|
+
if (decl.files) {
|
|
7835
|
+
for (const fileName of decl.files) {
|
|
7836
|
+
const fileAddr = { type: "file", name: fileName, provider };
|
|
7837
|
+
if (nodes.has(addressKey(fileAddr))) addEdge(agentAddr, fileAddr);
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7438
7840
|
if (decl.memory_stores) {
|
|
7439
7841
|
for (const msName of decl.memory_stores) {
|
|
7440
7842
|
const msAddr = {
|
|
@@ -7499,6 +7901,7 @@ function buildDependencyGraph(config, targetProviders) {
|
|
|
7499
7901
|
if (decl.provider && decl.provider !== provider) continue;
|
|
7500
7902
|
const channelAddr = { type: "channel", name, provider };
|
|
7501
7903
|
addNode(channelAddr);
|
|
7904
|
+
if (decl.mode === "pairing" || !decl.agent) continue;
|
|
7502
7905
|
const agentDecl = config.agents?.[decl.agent];
|
|
7503
7906
|
const agentType = agentDecl ? resolveAgentMaterialization(provider, agentDecl).resourceType : "agent";
|
|
7504
7907
|
const agentAddr = { type: agentType, name: decl.agent, provider };
|
|
@@ -7839,7 +8242,7 @@ async function refreshState(state, providers, options = {}) {
|
|
|
7839
8242
|
dirty = true;
|
|
7840
8243
|
continue;
|
|
7841
8244
|
}
|
|
7842
|
-
const remote = await provider.findResource(res.address.type, res.address.name, res.remote_id);
|
|
8245
|
+
const remote = await provider.findResource(res.address.type, res.address.name, res.remote_id, res.api_mode);
|
|
7843
8246
|
if (!remote) {
|
|
7844
8247
|
if (!options.quiet) {
|
|
7845
8248
|
emitRuntimeFeedback(options.onFeedback, {
|
|
@@ -8397,12 +8800,61 @@ function planDestroyProjectContext(ctx) {
|
|
|
8397
8800
|
const resources = [...ctx.state.listResources()].sort(
|
|
8398
8801
|
(a, b) => (destroyOrder[a.address.type] ?? 99) - (destroyOrder[b.address.type] ?? 99)
|
|
8399
8802
|
);
|
|
8400
|
-
|
|
8803
|
+
const identityName = ctx.config.defaults?.identity;
|
|
8804
|
+
const defaultMemoryStores = [];
|
|
8805
|
+
for (const [agentName, agent] of Object.entries(ctx.config.agents ?? {})) {
|
|
8806
|
+
if (!agent.default_memory_store || agent.delivery?.qoder?.type !== "forward") continue;
|
|
8807
|
+
if (agent.provider && agent.provider !== "qoder") continue;
|
|
8808
|
+
defaultMemoryStores.push({
|
|
8809
|
+
agentName,
|
|
8810
|
+
provider: "qoder",
|
|
8811
|
+
identityId: identityName ? ctx.state.getResource({ type: "identity", name: identityName, provider: "qoder" })?.remote_id ?? null : null,
|
|
8812
|
+
templateId: ctx.state.getResource({ type: "template", name: agentName, provider: "qoder" })?.remote_id ?? null,
|
|
8813
|
+
deleteOnDestroy: agent.default_memory_store.delete_on_destroy ?? false
|
|
8814
|
+
});
|
|
8815
|
+
}
|
|
8816
|
+
for (const pending of ctx.state.getStateFile().pending_default_memory_store_cleanups ?? []) {
|
|
8817
|
+
const existing = defaultMemoryStores.find(
|
|
8818
|
+
(item) => item.agentName === pending.agent_name && item.provider === pending.provider
|
|
8819
|
+
);
|
|
8820
|
+
if (existing) {
|
|
8821
|
+
existing.memoryStoreId = pending.remote_id;
|
|
8822
|
+
existing.deleteOnDestroy = true;
|
|
8823
|
+
} else {
|
|
8824
|
+
defaultMemoryStores.push({
|
|
8825
|
+
agentName: pending.agent_name,
|
|
8826
|
+
provider: pending.provider,
|
|
8827
|
+
identityId: pending.identity_id ?? null,
|
|
8828
|
+
templateId: pending.template_id ?? null,
|
|
8829
|
+
deleteOnDestroy: true,
|
|
8830
|
+
memoryStoreId: pending.remote_id
|
|
8831
|
+
});
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
return { resources, defaultMemoryStores, executionContext: ctx };
|
|
8401
8835
|
}
|
|
8402
8836
|
async function destroyPlannedProjectResources(planned, options = {}) {
|
|
8403
8837
|
const results = [];
|
|
8404
|
-
|
|
8838
|
+
const capturedDefaults = await captureDefaultMemoryStores(planned);
|
|
8405
8839
|
const ctx = planned.executionContext;
|
|
8840
|
+
if (capturedDefaults.some((item) => item.error)) {
|
|
8841
|
+
const defaultMemoryStoreResults2 = capturedDefaults.map(preflightFailureResult);
|
|
8842
|
+
for (const resource of planned.resources) {
|
|
8843
|
+
const result = {
|
|
8844
|
+
resource,
|
|
8845
|
+
status: "blocked",
|
|
8846
|
+
reason: "skipped",
|
|
8847
|
+
error: "Destroy aborted because the default Memory Store preflight failed."
|
|
8848
|
+
};
|
|
8849
|
+
results.push(result);
|
|
8850
|
+
options.onResourceResult?.(result);
|
|
8851
|
+
}
|
|
8852
|
+
return { ...planned, results, defaultMemoryStoreResults: defaultMemoryStoreResults2, destroyed: 0, partial: true };
|
|
8853
|
+
}
|
|
8854
|
+
if (await persistCapturedDefaultMemoryStores(ctx, capturedDefaults)) {
|
|
8855
|
+
await ctx.state.save();
|
|
8856
|
+
}
|
|
8857
|
+
let stateChanged = false;
|
|
8406
8858
|
for (const resource of planned.resources) {
|
|
8407
8859
|
options.onResourceStart?.(resource);
|
|
8408
8860
|
const result = await destroyOneResource(ctx, resource, options);
|
|
@@ -8413,14 +8865,171 @@ async function destroyPlannedProjectResources(planned, options = {}) {
|
|
|
8413
8865
|
if (stateChanged) {
|
|
8414
8866
|
await ctx.state.save();
|
|
8415
8867
|
}
|
|
8868
|
+
const defaultMemoryStoreResults = await finalizeDefaultMemoryStores(planned, capturedDefaults, options);
|
|
8869
|
+
if (recordFailedDefaultMemoryStoreCleanups(ctx, defaultMemoryStoreResults)) {
|
|
8870
|
+
await ctx.state.save();
|
|
8871
|
+
}
|
|
8872
|
+
if (clearCompletedDefaultMemoryStoreCleanups(ctx, defaultMemoryStoreResults)) {
|
|
8873
|
+
await ctx.state.save();
|
|
8874
|
+
}
|
|
8416
8875
|
const destroyed = results.filter((result) => result.status === "success").length;
|
|
8417
8876
|
return {
|
|
8418
8877
|
...planned,
|
|
8419
8878
|
results,
|
|
8879
|
+
defaultMemoryStoreResults,
|
|
8420
8880
|
destroyed,
|
|
8421
|
-
partial: destroyed !== planned.resources.length
|
|
8881
|
+
partial: destroyed !== planned.resources.length || defaultMemoryStoreResults.some((result) => result.status === "failed")
|
|
8882
|
+
};
|
|
8883
|
+
}
|
|
8884
|
+
async function persistCapturedDefaultMemoryStores(ctx, captured) {
|
|
8885
|
+
const state = ctx.state.getStateFile();
|
|
8886
|
+
if (!state.pending_default_memory_store_cleanups) state.pending_default_memory_store_cleanups = [];
|
|
8887
|
+
const pending = state.pending_default_memory_store_cleanups;
|
|
8888
|
+
let changed = false;
|
|
8889
|
+
for (const item of captured) {
|
|
8890
|
+
if (!item.plan.deleteOnDestroy || !item.memoryStoreId) continue;
|
|
8891
|
+
if (pending.some((entry) => entry.provider === item.plan.provider && entry.remote_id === item.memoryStoreId))
|
|
8892
|
+
continue;
|
|
8893
|
+
pending.push({
|
|
8894
|
+
agent_name: item.plan.agentName,
|
|
8895
|
+
provider: item.plan.provider,
|
|
8896
|
+
remote_id: item.memoryStoreId,
|
|
8897
|
+
...item.plan.identityId ? { identity_id: item.plan.identityId } : {},
|
|
8898
|
+
...item.plan.templateId ? { template_id: item.plan.templateId } : {}
|
|
8899
|
+
});
|
|
8900
|
+
changed = true;
|
|
8901
|
+
}
|
|
8902
|
+
return changed;
|
|
8903
|
+
}
|
|
8904
|
+
function clearCompletedDefaultMemoryStoreCleanups(ctx, results) {
|
|
8905
|
+
const state = ctx.state.getStateFile();
|
|
8906
|
+
const completedIds = new Set(
|
|
8907
|
+
results.filter((item) => item.status === "deleted" || item.status === "already_gone").map((item) => item.memoryStoreId).filter((id) => Boolean(id))
|
|
8908
|
+
);
|
|
8909
|
+
if (completedIds.size === 0 || !state.pending_default_memory_store_cleanups?.length) return false;
|
|
8910
|
+
const remaining = state.pending_default_memory_store_cleanups.filter((item) => !completedIds.has(item.remote_id));
|
|
8911
|
+
if (remaining.length === state.pending_default_memory_store_cleanups.length) return false;
|
|
8912
|
+
state.pending_default_memory_store_cleanups = remaining;
|
|
8913
|
+
return true;
|
|
8914
|
+
}
|
|
8915
|
+
function recordFailedDefaultMemoryStoreCleanups(ctx, results) {
|
|
8916
|
+
const pending = ctx.state.getStateFile().pending_default_memory_store_cleanups;
|
|
8917
|
+
if (!pending?.length) return false;
|
|
8918
|
+
let changed = false;
|
|
8919
|
+
for (const result of results) {
|
|
8920
|
+
if (result.status !== "failed" || !result.memoryStoreId) continue;
|
|
8921
|
+
const entry = pending.find((item) => item.remote_id === result.memoryStoreId);
|
|
8922
|
+
if (entry && entry.last_error !== result.error) {
|
|
8923
|
+
entry.last_error = result.error;
|
|
8924
|
+
changed = true;
|
|
8925
|
+
}
|
|
8926
|
+
}
|
|
8927
|
+
return changed;
|
|
8928
|
+
}
|
|
8929
|
+
function preflightFailureResult(item) {
|
|
8930
|
+
if (!item.plan.deleteOnDestroy) return { ...item.plan, status: "retained" };
|
|
8931
|
+
return {
|
|
8932
|
+
...item.plan,
|
|
8933
|
+
status: "failed",
|
|
8934
|
+
...item.memoryStoreId ? { memoryStoreId: item.memoryStoreId } : {},
|
|
8935
|
+
error: item.error ?? "Destroy aborted because another default Memory Store preflight failed."
|
|
8422
8936
|
};
|
|
8423
8937
|
}
|
|
8938
|
+
async function captureDefaultMemoryStores(planned) {
|
|
8939
|
+
return Promise.all(
|
|
8940
|
+
planned.defaultMemoryStores.map(async (item) => {
|
|
8941
|
+
if (!item.deleteOnDestroy) return { plan: item };
|
|
8942
|
+
if (item.memoryStoreId) return { plan: item, memoryStoreId: item.memoryStoreId };
|
|
8943
|
+
if (!item.identityId || !item.templateId) {
|
|
8944
|
+
return { plan: item, error: "Cannot resolve the Identity and Template before destroy." };
|
|
8945
|
+
}
|
|
8946
|
+
try {
|
|
8947
|
+
const provider = getRuntimeProvider(planned.executionContext, item.provider);
|
|
8948
|
+
if (!provider.findDefaultMemoryStoreId || !provider.deleteDefaultMemoryStore) {
|
|
8949
|
+
return { plan: item, error: `Provider '${item.provider}' cannot delete a default memory store.` };
|
|
8950
|
+
}
|
|
8951
|
+
const memoryStoreId = await provider.findDefaultMemoryStoreId(item.identityId, item.templateId);
|
|
8952
|
+
return { plan: item, ...memoryStoreId ? { memoryStoreId } : {} };
|
|
8953
|
+
} catch (error) {
|
|
8954
|
+
return { plan: item, error: error instanceof Error ? error.message : String(error) };
|
|
8955
|
+
}
|
|
8956
|
+
})
|
|
8957
|
+
);
|
|
8958
|
+
}
|
|
8959
|
+
async function finalizeDefaultMemoryStores(planned, captured, options) {
|
|
8960
|
+
const output = [];
|
|
8961
|
+
for (const item of captured) {
|
|
8962
|
+
if (!item.plan.deleteOnDestroy) {
|
|
8963
|
+
output.push({ ...item.plan, status: "retained" });
|
|
8964
|
+
continue;
|
|
8965
|
+
}
|
|
8966
|
+
if (item.error) {
|
|
8967
|
+
output.push({ ...item.plan, status: "failed", error: item.error });
|
|
8968
|
+
continue;
|
|
8969
|
+
}
|
|
8970
|
+
if (!item.memoryStoreId) {
|
|
8971
|
+
output.push({ ...item.plan, status: "already_gone" });
|
|
8972
|
+
continue;
|
|
8973
|
+
}
|
|
8974
|
+
try {
|
|
8975
|
+
const provider = getRuntimeProvider(planned.executionContext, item.plan.provider);
|
|
8976
|
+
await deleteDefaultMemoryStoreWithArchiveFallback(
|
|
8977
|
+
provider,
|
|
8978
|
+
item.memoryStoreId,
|
|
8979
|
+
options.defaultMemoryStoreRetryDelaysMs ?? [1e3, 2e3, 4e3, 8e3]
|
|
8980
|
+
);
|
|
8981
|
+
output.push({ ...item.plan, status: "deleted", memoryStoreId: item.memoryStoreId });
|
|
8982
|
+
} catch (error) {
|
|
8983
|
+
if (ApiError.isNotFound(error)) {
|
|
8984
|
+
output.push({ ...item.plan, status: "already_gone", memoryStoreId: item.memoryStoreId });
|
|
8985
|
+
} else {
|
|
8986
|
+
output.push({
|
|
8987
|
+
...item.plan,
|
|
8988
|
+
status: "failed",
|
|
8989
|
+
memoryStoreId: item.memoryStoreId,
|
|
8990
|
+
error: error instanceof Error ? error.message : String(error)
|
|
8991
|
+
});
|
|
8992
|
+
}
|
|
8993
|
+
}
|
|
8994
|
+
}
|
|
8995
|
+
return output;
|
|
8996
|
+
}
|
|
8997
|
+
async function deleteDefaultMemoryStoreWithArchiveFallback(provider, memoryStoreId, retryDelaysMs) {
|
|
8998
|
+
try {
|
|
8999
|
+
await retryDefaultMemoryStoreOperation(() => provider.deleteDefaultMemoryStore(memoryStoreId), retryDelaysMs);
|
|
9000
|
+
} catch (error) {
|
|
9001
|
+
if (isAlreadyArchivedConflict(error) && provider.deleteMemoryStore) {
|
|
9002
|
+
await retryDefaultMemoryStoreOperation(() => provider.deleteMemoryStore(memoryStoreId), retryDelaysMs);
|
|
9003
|
+
return;
|
|
9004
|
+
}
|
|
9005
|
+
if (!isStillMountedConflict(error) || !provider.archiveMemoryStore || !provider.deleteMemoryStore) throw error;
|
|
9006
|
+
await retryDefaultMemoryStoreOperation(() => provider.archiveMemoryStore(memoryStoreId), retryDelaysMs);
|
|
9007
|
+
await retryDefaultMemoryStoreOperation(() => provider.deleteMemoryStore(memoryStoreId), retryDelaysMs);
|
|
9008
|
+
}
|
|
9009
|
+
}
|
|
9010
|
+
async function retryDefaultMemoryStoreOperation(operation, delaysMs) {
|
|
9011
|
+
for (let attempt = 0; ; attempt++) {
|
|
9012
|
+
try {
|
|
9013
|
+
await operation();
|
|
9014
|
+
return;
|
|
9015
|
+
} catch (error) {
|
|
9016
|
+
if (!isRetryableDefaultMemoryStoreError(error) || attempt >= delaysMs.length) throw error;
|
|
9017
|
+
await delay(delaysMs[attempt]);
|
|
9018
|
+
}
|
|
9019
|
+
}
|
|
9020
|
+
}
|
|
9021
|
+
function isRetryableDefaultMemoryStoreError(error) {
|
|
9022
|
+
return error instanceof ApiError && (isStillMountedConflict(error) || isAlreadyArchivedConflict(error) || error.statusCode === 429 || [500, 502, 503].includes(error.statusCode));
|
|
9023
|
+
}
|
|
9024
|
+
function isStillMountedConflict(error) {
|
|
9025
|
+
return error instanceof ApiError && error.statusCode === 409 && error.responseBody.includes("still mounted");
|
|
9026
|
+
}
|
|
9027
|
+
function isAlreadyArchivedConflict(error) {
|
|
9028
|
+
return error instanceof ApiError && error.statusCode === 409 && error.responseBody.toLowerCase().includes("already archived");
|
|
9029
|
+
}
|
|
9030
|
+
function delay(ms) {
|
|
9031
|
+
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
9032
|
+
}
|
|
8424
9033
|
async function destroyOneResource(ctx, resource, options) {
|
|
8425
9034
|
if (isExternalReference(ctx, resource)) {
|
|
8426
9035
|
ctx.state.removeResource(resource.address);
|
|
@@ -8441,8 +9050,18 @@ async function destroyOneResource(ctx, resource, options) {
|
|
|
8441
9050
|
ctx.state.removeResource(resource.address);
|
|
8442
9051
|
return successResult(resource, "destroyed");
|
|
8443
9052
|
}
|
|
9053
|
+
const apiMode = resource.api_mode === "auto" ? void 0 : resource.api_mode;
|
|
8444
9054
|
try {
|
|
8445
|
-
await deleteRemoteResource(
|
|
9055
|
+
await deleteRemoteResource(
|
|
9056
|
+
provider,
|
|
9057
|
+
resource.address.type,
|
|
9058
|
+
resource.remote_id,
|
|
9059
|
+
options.cascade,
|
|
9060
|
+
apiMode,
|
|
9061
|
+
ctx.state.listResources().filter(
|
|
9062
|
+
(candidate) => candidate.address.provider === resource.address.provider && candidate.address.type === "memory_store" && candidate.api_mode === "forward" && typeof candidate.remote_id === "string"
|
|
9063
|
+
).map((candidate) => candidate.remote_id)
|
|
9064
|
+
);
|
|
8446
9065
|
ctx.state.removeResource(resource.address);
|
|
8447
9066
|
emitRuntimeFeedback(options.onFeedback, {
|
|
8448
9067
|
type: "resource_action_success",
|
|
@@ -8471,7 +9090,7 @@ async function destroyOneResource(ctx, resource, options) {
|
|
|
8471
9090
|
};
|
|
8472
9091
|
if (await options.onCascadeRequired?.(blocked)) {
|
|
8473
9092
|
try {
|
|
8474
|
-
await provider.deleteEnvironment(resource.remote_id, true);
|
|
9093
|
+
await provider.deleteEnvironment(resource.remote_id, true, apiMode);
|
|
8475
9094
|
ctx.state.removeResource(resource.address);
|
|
8476
9095
|
return {
|
|
8477
9096
|
...successResult(resource, "destroyed"),
|
|
@@ -8507,29 +9126,29 @@ function failureResult(resource, error) {
|
|
|
8507
9126
|
error: error instanceof Error ? error.message : String(error)
|
|
8508
9127
|
};
|
|
8509
9128
|
}
|
|
8510
|
-
async function deleteRemoteResource(provider, type, id, cascade) {
|
|
9129
|
+
async function deleteRemoteResource(provider, type, id, cascade, mode, ownedMemoryStoreIds = []) {
|
|
8511
9130
|
switch (type) {
|
|
8512
9131
|
case "agent":
|
|
8513
9132
|
await provider.deleteAgent(id);
|
|
8514
9133
|
return;
|
|
8515
9134
|
case "template":
|
|
8516
9135
|
if (!provider.archiveTemplate) throw new UserError(`Provider does not support templates`);
|
|
8517
|
-
await provider.archiveTemplate(id);
|
|
9136
|
+
await provider.archiveTemplate(id, ownedMemoryStoreIds);
|
|
8518
9137
|
return;
|
|
8519
9138
|
case "skill":
|
|
8520
|
-
await provider.deleteSkill(id);
|
|
9139
|
+
await provider.deleteSkill(id, mode);
|
|
8521
9140
|
return;
|
|
8522
9141
|
case "memory_store":
|
|
8523
9142
|
if (!provider.deleteMemoryStore) {
|
|
8524
9143
|
throw new UserError(`Provider does not support memory stores`);
|
|
8525
9144
|
}
|
|
8526
|
-
await provider.deleteMemoryStore(id);
|
|
9145
|
+
await provider.deleteMemoryStore(id, mode);
|
|
8527
9146
|
return;
|
|
8528
9147
|
case "vault":
|
|
8529
|
-
await provider.deleteVault(id);
|
|
9148
|
+
await provider.deleteVault(id, mode);
|
|
8530
9149
|
return;
|
|
8531
9150
|
case "environment":
|
|
8532
|
-
await provider.deleteEnvironment(id, cascade);
|
|
9151
|
+
await provider.deleteEnvironment(id, cascade, mode);
|
|
8533
9152
|
return;
|
|
8534
9153
|
case "deployment":
|
|
8535
9154
|
await provider.deleteDeployment(id);
|
|
@@ -8543,7 +9162,7 @@ async function deleteRemoteResource(provider, type, id, cascade) {
|
|
|
8543
9162
|
await provider.deleteChannel(id);
|
|
8544
9163
|
return;
|
|
8545
9164
|
case "file":
|
|
8546
|
-
await provider.deleteFile(id);
|
|
9165
|
+
await provider.deleteFile(id, mode);
|
|
8547
9166
|
return;
|
|
8548
9167
|
}
|
|
8549
9168
|
}
|
|
@@ -9308,7 +9927,7 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
|
|
|
9308
9927
|
terminalStatus = terminalEvent.status;
|
|
9309
9928
|
break;
|
|
9310
9929
|
}
|
|
9311
|
-
await
|
|
9930
|
+
await delay2(currentIntervalMs);
|
|
9312
9931
|
currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
|
|
9313
9932
|
}
|
|
9314
9933
|
} else {
|
|
@@ -9319,7 +9938,7 @@ async function collectEventsUntilTerminal(adapter2, sessionId, options = {}) {
|
|
|
9319
9938
|
terminalStatus = session.status;
|
|
9320
9939
|
break;
|
|
9321
9940
|
}
|
|
9322
|
-
await
|
|
9941
|
+
await delay2(currentIntervalMs);
|
|
9323
9942
|
currentIntervalMs = Math.min(currentIntervalMs * 2, maxPollIntervalMs);
|
|
9324
9943
|
}
|
|
9325
9944
|
result = await adapter2.listSessionEvents(sessionId, { limit: 100 });
|
|
@@ -9486,7 +10105,7 @@ async function* streamWithResume(adapter2, sessionId, message) {
|
|
|
9486
10105
|
}
|
|
9487
10106
|
}
|
|
9488
10107
|
if (!reachedTerminal) {
|
|
9489
|
-
await
|
|
10108
|
+
await delay2(reconnectIntervalMs);
|
|
9490
10109
|
reconnectIntervalMs = Math.min(reconnectIntervalMs * 2, DEFAULT_POLL_INTERVAL_MS);
|
|
9491
10110
|
}
|
|
9492
10111
|
}
|
|
@@ -9514,7 +10133,7 @@ function assertNotTimedOut(start, timeoutMs) {
|
|
|
9514
10133
|
throw new UserError(`Session did not complete within the timeout (${Math.floor(timeoutMs / 1e3)} seconds).`);
|
|
9515
10134
|
}
|
|
9516
10135
|
}
|
|
9517
|
-
function
|
|
10136
|
+
function delay2(ms) {
|
|
9518
10137
|
return new Promise((resolve13) => setTimeout(resolve13, ms));
|
|
9519
10138
|
}
|
|
9520
10139
|
|
|
@@ -9700,6 +10319,7 @@ var StateManager = class _StateManager {
|
|
|
9700
10319
|
address: r.address,
|
|
9701
10320
|
remote_id: r.remote_id,
|
|
9702
10321
|
externally_managed: r.externally_managed === true ? true : void 0,
|
|
10322
|
+
api_mode: r.api_mode === "forward" ? "forward" : r.api_mode === "managed" ? "managed" : void 0,
|
|
9703
10323
|
version: r.version,
|
|
9704
10324
|
content_hash: r.content_hash ?? r.desired_hash ?? "",
|
|
9705
10325
|
desired_hash: r.desired_hash ?? r.content_hash ?? "",
|
|
@@ -9711,7 +10331,11 @@ var StateManager = class _StateManager {
|
|
|
9711
10331
|
drift_paths: r.drift_paths,
|
|
9712
10332
|
drift_status: r.drift_status
|
|
9713
10333
|
}));
|
|
9714
|
-
|
|
10334
|
+
const pending = Array.isArray(data.pending_default_memory_store_cleanups) ? data.pending_default_memory_store_cleanups : void 0;
|
|
10335
|
+
return new _StateManager(
|
|
10336
|
+
{ resources, ...pending ? { pending_default_memory_store_cleanups: pending } : {} },
|
|
10337
|
+
path
|
|
10338
|
+
);
|
|
9715
10339
|
} catch (err) {
|
|
9716
10340
|
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
9717
10341
|
return _StateManager.initialize(path);
|