@axiom-lattice/core 2.1.76 → 2.1.78
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/README.md +258 -0
- package/dist/index.d.mts +539 -30
- package/dist/index.d.ts +539 -30
- package/dist/index.js +678 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +658 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -42,6 +42,7 @@ __export(index_exports, {
|
|
|
42
42
|
CompositeBackend: () => CompositeBackend,
|
|
43
43
|
ConsoleLoggerClient: () => ConsoleLoggerClient,
|
|
44
44
|
CustomMetricsClient: () => CustomMetricsClient,
|
|
45
|
+
CustomMiddlewareRegistry: () => CustomMiddlewareRegistry,
|
|
45
46
|
DaytonaInstance: () => DaytonaInstance,
|
|
46
47
|
DaytonaProvider: () => DaytonaProvider,
|
|
47
48
|
DefaultScheduleClient: () => DefaultScheduleClient,
|
|
@@ -51,7 +52,8 @@ __export(index_exports, {
|
|
|
51
52
|
EmbeddingsLatticeManager: () => EmbeddingsLatticeManager,
|
|
52
53
|
FileSystemSkillStore: () => FileSystemSkillStore,
|
|
53
54
|
FilesystemBackend: () => FilesystemBackend,
|
|
54
|
-
HumanMessage: () =>
|
|
55
|
+
HumanMessage: () => import_messages6.HumanMessage,
|
|
56
|
+
InMemoryA2AApiKeyStore: () => InMemoryA2AApiKeyStore,
|
|
55
57
|
InMemoryAssistantStore: () => InMemoryAssistantStore,
|
|
56
58
|
InMemoryBindingStore: () => InMemoryBindingStore,
|
|
57
59
|
InMemoryChannelInstallationStore: () => InMemoryChannelInstallationStore,
|
|
@@ -1893,6 +1895,7 @@ var InMemoryProjectStore = class {
|
|
|
1893
1895
|
workspaceId,
|
|
1894
1896
|
name: data.name,
|
|
1895
1897
|
description: data.description,
|
|
1898
|
+
config: data.config,
|
|
1896
1899
|
createdAt: now,
|
|
1897
1900
|
updatedAt: now
|
|
1898
1901
|
};
|
|
@@ -1900,6 +1903,13 @@ var InMemoryProjectStore = class {
|
|
|
1900
1903
|
this.projects.set(key, project);
|
|
1901
1904
|
return project;
|
|
1902
1905
|
}
|
|
1906
|
+
/**
|
|
1907
|
+
* Update an existing project
|
|
1908
|
+
*
|
|
1909
|
+
* @remarks
|
|
1910
|
+
* - The `config` field uses **replace** semantics: if provided, it completely
|
|
1911
|
+
* overwrites the existing config. To preserve the current config, omit this field.
|
|
1912
|
+
*/
|
|
1903
1913
|
async updateProject(tenantId, id, updates) {
|
|
1904
1914
|
const key = this.getKey(tenantId, id);
|
|
1905
1915
|
const existing = this.projects.get(key);
|
|
@@ -2691,14 +2701,35 @@ var InMemoryChannelInstallationStore = class {
|
|
|
2691
2701
|
constructor() {
|
|
2692
2702
|
this.installations = /* @__PURE__ */ new Map();
|
|
2693
2703
|
}
|
|
2704
|
+
/**
|
|
2705
|
+
* Retrieves a channel installation by its unique ID.
|
|
2706
|
+
*
|
|
2707
|
+
* @param installationId - The installation identifier
|
|
2708
|
+
* @returns The {@link ChannelInstallation} or `null` if not found
|
|
2709
|
+
*/
|
|
2694
2710
|
async getInstallationById(installationId) {
|
|
2695
2711
|
return this.installations.get(installationId) || null;
|
|
2696
2712
|
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Lists all channel installations for a tenant, optionally filtered by channel type.
|
|
2715
|
+
*
|
|
2716
|
+
* @param tenantId - Tenant identifier
|
|
2717
|
+
* @param channel - Optional channel type filter (`"lark"`, `"email"`, `"slack"`)
|
|
2718
|
+
* @returns Array of matching {@link ChannelInstallation} objects
|
|
2719
|
+
*/
|
|
2697
2720
|
async getInstallationsByTenant(tenantId, channel) {
|
|
2698
2721
|
return Array.from(this.installations.values()).filter(
|
|
2699
2722
|
(inst) => inst.tenantId === tenantId && (!channel || inst.channel === channel)
|
|
2700
2723
|
);
|
|
2701
2724
|
}
|
|
2725
|
+
/**
|
|
2726
|
+
* Creates a new channel installation for a tenant.
|
|
2727
|
+
*
|
|
2728
|
+
* @param tenantId - Tenant identifier
|
|
2729
|
+
* @param installationId - Unique installation ID (caller-defined)
|
|
2730
|
+
* @param data - {@link CreateChannelInstallationRequest} containing channel type, name, config, and fallback settings
|
|
2731
|
+
* @returns The created {@link ChannelInstallation}
|
|
2732
|
+
*/
|
|
2702
2733
|
async createInstallation(tenantId, installationId, data) {
|
|
2703
2734
|
const now = /* @__PURE__ */ new Date();
|
|
2704
2735
|
const installation = {
|
|
@@ -2716,6 +2747,14 @@ var InMemoryChannelInstallationStore = class {
|
|
|
2716
2747
|
this.installations.set(installationId, installation);
|
|
2717
2748
|
return installation;
|
|
2718
2749
|
}
|
|
2750
|
+
/**
|
|
2751
|
+
* Updates an existing channel installation. Config fields are shallow-merged.
|
|
2752
|
+
*
|
|
2753
|
+
* @param tenantId - Tenant identifier (used for isolation check)
|
|
2754
|
+
* @param installationId - Installation ID to update
|
|
2755
|
+
* @param updates - {@link UpdateChannelInstallationRequest} with fields to patch
|
|
2756
|
+
* @returns The updated {@link ChannelInstallation} or `null` if not found or tenant mismatch
|
|
2757
|
+
*/
|
|
2719
2758
|
async updateInstallation(tenantId, installationId, updates) {
|
|
2720
2759
|
const existing = this.installations.get(installationId);
|
|
2721
2760
|
if (!existing || existing.tenantId !== tenantId) return null;
|
|
@@ -2731,11 +2770,21 @@ var InMemoryChannelInstallationStore = class {
|
|
|
2731
2770
|
this.installations.set(installationId, updated);
|
|
2732
2771
|
return updated;
|
|
2733
2772
|
}
|
|
2773
|
+
/**
|
|
2774
|
+
* Deletes a channel installation.
|
|
2775
|
+
*
|
|
2776
|
+
* @param tenantId - Tenant identifier (used for isolation check)
|
|
2777
|
+
* @param installationId - Installation ID to delete
|
|
2778
|
+
* @returns `true` if deleted, `false` if not found or tenant mismatch
|
|
2779
|
+
*/
|
|
2734
2780
|
async deleteInstallation(tenantId, installationId) {
|
|
2735
2781
|
const existing = this.installations.get(installationId);
|
|
2736
2782
|
if (!existing || existing.tenantId !== tenantId) return false;
|
|
2737
2783
|
return this.installations.delete(installationId);
|
|
2738
2784
|
}
|
|
2785
|
+
/**
|
|
2786
|
+
* Clears all in-memory installations. Primarily used in tests.
|
|
2787
|
+
*/
|
|
2739
2788
|
clear() {
|
|
2740
2789
|
this.installations.clear();
|
|
2741
2790
|
}
|
|
@@ -2747,6 +2796,16 @@ var InMemoryBindingStore = class {
|
|
|
2747
2796
|
constructor() {
|
|
2748
2797
|
this.bindings = /* @__PURE__ */ new Map();
|
|
2749
2798
|
}
|
|
2799
|
+
/**
|
|
2800
|
+
* Resolves a binding for the given sender across a specific channel installation.
|
|
2801
|
+
*
|
|
2802
|
+
* Called by `MessageRouter.dispatch()` during inbound message processing.
|
|
2803
|
+
* Matches on `channel + senderId + channelInstallationId + tenantId` and
|
|
2804
|
+
* requires `enabled === true`.
|
|
2805
|
+
*
|
|
2806
|
+
* @param params - Resolution parameters
|
|
2807
|
+
* @returns The matching {@link Binding} or `null` if none found.
|
|
2808
|
+
*/
|
|
2750
2809
|
async resolve(params) {
|
|
2751
2810
|
for (const binding of this.bindings.values()) {
|
|
2752
2811
|
if (binding.channel === params.channel && binding.senderId === params.senderId && binding.channelInstallationId === params.channelInstallationId && binding.tenantId === params.tenantId && binding.enabled) {
|
|
@@ -2755,6 +2814,12 @@ var InMemoryBindingStore = class {
|
|
|
2755
2814
|
}
|
|
2756
2815
|
return null;
|
|
2757
2816
|
}
|
|
2817
|
+
/**
|
|
2818
|
+
* Creates a new sender-to-agent binding.
|
|
2819
|
+
*
|
|
2820
|
+
* @param input - {@link CreateBindingInput} defining channel, sender, target agent, and thread mode.
|
|
2821
|
+
* @returns The newly created {@link Binding}.
|
|
2822
|
+
*/
|
|
2758
2823
|
async create(input) {
|
|
2759
2824
|
const now = /* @__PURE__ */ new Date();
|
|
2760
2825
|
const binding = {
|
|
@@ -2777,6 +2842,14 @@ var InMemoryBindingStore = class {
|
|
|
2777
2842
|
this.bindings.set(binding.id, binding);
|
|
2778
2843
|
return binding;
|
|
2779
2844
|
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Updates an existing binding (e.g. changing the target agent or thread mode).
|
|
2847
|
+
*
|
|
2848
|
+
* @param id - Binding ID
|
|
2849
|
+
* @param patch - Partial {@link Binding} fields to update
|
|
2850
|
+
* @returns The updated {@link Binding}
|
|
2851
|
+
* @throws {Error} If the binding does not exist
|
|
2852
|
+
*/
|
|
2780
2853
|
async update(id, patch) {
|
|
2781
2854
|
const existing = this.bindings.get(id);
|
|
2782
2855
|
if (!existing) throw new Error(`Binding ${id} not found`);
|
|
@@ -2788,9 +2861,20 @@ var InMemoryBindingStore = class {
|
|
|
2788
2861
|
this.bindings.set(id, updated);
|
|
2789
2862
|
return updated;
|
|
2790
2863
|
}
|
|
2864
|
+
/**
|
|
2865
|
+
* Deletes a binding by ID.
|
|
2866
|
+
*
|
|
2867
|
+
* @param id - Binding ID
|
|
2868
|
+
*/
|
|
2791
2869
|
async delete(id) {
|
|
2792
2870
|
this.bindings.delete(id);
|
|
2793
2871
|
}
|
|
2872
|
+
/**
|
|
2873
|
+
* Lists bindings filtered by tenant and optional channel/agent/installation.
|
|
2874
|
+
*
|
|
2875
|
+
* @param params - Filter and pagination parameters
|
|
2876
|
+
* @returns Array of matching {@link Binding} objects
|
|
2877
|
+
*/
|
|
2794
2878
|
async list(params) {
|
|
2795
2879
|
let results = Array.from(this.bindings.values()).filter((b) => {
|
|
2796
2880
|
if (b.tenantId !== params.tenantId) return false;
|
|
@@ -2803,6 +2887,12 @@ var InMemoryBindingStore = class {
|
|
|
2803
2887
|
const limit = params.limit ?? 50;
|
|
2804
2888
|
return results.slice(offset, offset + limit);
|
|
2805
2889
|
}
|
|
2890
|
+
/**
|
|
2891
|
+
* Bulk-imports bindings.
|
|
2892
|
+
*
|
|
2893
|
+
* @param bindings - Array of {@link CreateBindingInput}
|
|
2894
|
+
* @returns Array of created {@link Binding} objects
|
|
2895
|
+
*/
|
|
2806
2896
|
async import(bindings) {
|
|
2807
2897
|
const result = [];
|
|
2808
2898
|
for (const input of bindings) {
|
|
@@ -2810,14 +2900,104 @@ var InMemoryBindingStore = class {
|
|
|
2810
2900
|
}
|
|
2811
2901
|
return result;
|
|
2812
2902
|
}
|
|
2903
|
+
/**
|
|
2904
|
+
* Exports all bindings for a tenant.
|
|
2905
|
+
*
|
|
2906
|
+
* @param params - Filter by tenantId
|
|
2907
|
+
* @returns Array of {@link Binding} objects
|
|
2908
|
+
*/
|
|
2813
2909
|
async export(params) {
|
|
2814
2910
|
return this.list({ tenantId: params.tenantId, limit: 1e4 });
|
|
2815
2911
|
}
|
|
2912
|
+
/**
|
|
2913
|
+
* Clears all in-memory bindings. Primarily used in tests.
|
|
2914
|
+
*/
|
|
2816
2915
|
clear() {
|
|
2817
2916
|
this.bindings.clear();
|
|
2818
2917
|
}
|
|
2819
2918
|
};
|
|
2820
2919
|
|
|
2920
|
+
// src/store_lattice/InMemoryA2AApiKeyStore.ts
|
|
2921
|
+
var import_crypto2 = require("crypto");
|
|
2922
|
+
function generateApiKey() {
|
|
2923
|
+
return `a2a_${(0, import_crypto2.randomUUID)().replace(/-/g, "")}`;
|
|
2924
|
+
}
|
|
2925
|
+
var InMemoryA2AApiKeyStore = class {
|
|
2926
|
+
constructor() {
|
|
2927
|
+
this.keys = /* @__PURE__ */ new Map();
|
|
2928
|
+
}
|
|
2929
|
+
async findByKey(key) {
|
|
2930
|
+
for (const record of this.keys.values()) {
|
|
2931
|
+
if (record.key === key && record.enabled) return record;
|
|
2932
|
+
}
|
|
2933
|
+
return null;
|
|
2934
|
+
}
|
|
2935
|
+
async list(params) {
|
|
2936
|
+
let records = Array.from(this.keys.values());
|
|
2937
|
+
if (params.tenantId) {
|
|
2938
|
+
records = records.filter((r) => r.tenantId === params.tenantId);
|
|
2939
|
+
}
|
|
2940
|
+
const offset = params.offset || 0;
|
|
2941
|
+
const limit = params.limit;
|
|
2942
|
+
records = records.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2943
|
+
return limit ? records.slice(offset, offset + limit) : records.slice(offset);
|
|
2944
|
+
}
|
|
2945
|
+
async create(input) {
|
|
2946
|
+
const now = /* @__PURE__ */ new Date();
|
|
2947
|
+
const record = {
|
|
2948
|
+
id: (0, import_crypto2.randomUUID)(),
|
|
2949
|
+
key: generateApiKey(),
|
|
2950
|
+
tenantId: input.tenantId,
|
|
2951
|
+
projectId: input.projectId,
|
|
2952
|
+
workspaceId: input.workspaceId,
|
|
2953
|
+
label: input.label,
|
|
2954
|
+
enabled: true,
|
|
2955
|
+
createdAt: now,
|
|
2956
|
+
updatedAt: now
|
|
2957
|
+
};
|
|
2958
|
+
this.keys.set(record.id, record);
|
|
2959
|
+
return record;
|
|
2960
|
+
}
|
|
2961
|
+
async disable(id) {
|
|
2962
|
+
const record = this.keys.get(id);
|
|
2963
|
+
if (!record) throw new Error(`A2A API key not found: ${id}`);
|
|
2964
|
+
const updated = { ...record, enabled: false, updatedAt: /* @__PURE__ */ new Date() };
|
|
2965
|
+
this.keys.set(id, updated);
|
|
2966
|
+
return updated;
|
|
2967
|
+
}
|
|
2968
|
+
async enable(id) {
|
|
2969
|
+
const record = this.keys.get(id);
|
|
2970
|
+
if (!record) throw new Error(`A2A API key not found: ${id}`);
|
|
2971
|
+
const updated = { ...record, enabled: true, updatedAt: /* @__PURE__ */ new Date() };
|
|
2972
|
+
this.keys.set(id, updated);
|
|
2973
|
+
return updated;
|
|
2974
|
+
}
|
|
2975
|
+
async rotate(id) {
|
|
2976
|
+
const record = this.keys.get(id);
|
|
2977
|
+
if (!record) throw new Error(`A2A API key not found: ${id}`);
|
|
2978
|
+
const updated = { ...record, key: generateApiKey(), updatedAt: /* @__PURE__ */ new Date() };
|
|
2979
|
+
this.keys.set(id, updated);
|
|
2980
|
+
return updated;
|
|
2981
|
+
}
|
|
2982
|
+
async delete(id) {
|
|
2983
|
+
this.keys.delete(id);
|
|
2984
|
+
}
|
|
2985
|
+
async loadIntoMap() {
|
|
2986
|
+
const map = /* @__PURE__ */ new Map();
|
|
2987
|
+
for (const record of this.keys.values()) {
|
|
2988
|
+
if (record.enabled) {
|
|
2989
|
+
map.set(record.key, {
|
|
2990
|
+
key: record.key,
|
|
2991
|
+
tenantId: record.tenantId,
|
|
2992
|
+
projectId: record.projectId,
|
|
2993
|
+
workspaceId: record.workspaceId
|
|
2994
|
+
});
|
|
2995
|
+
}
|
|
2996
|
+
}
|
|
2997
|
+
return map;
|
|
2998
|
+
}
|
|
2999
|
+
};
|
|
3000
|
+
|
|
2821
3001
|
// src/store_lattice/StoreLatticeManager.ts
|
|
2822
3002
|
var StoreLatticeManager = class _StoreLatticeManager extends BaseLatticeManager {
|
|
2823
3003
|
/**
|
|
@@ -2992,6 +3172,12 @@ storeLatticeManager.registerLattice(
|
|
|
2992
3172
|
"channelBinding",
|
|
2993
3173
|
defaultChannelBindingStore
|
|
2994
3174
|
);
|
|
3175
|
+
var defaultA2AApiKeyStore = new InMemoryA2AApiKeyStore();
|
|
3176
|
+
storeLatticeManager.registerLattice(
|
|
3177
|
+
"default",
|
|
3178
|
+
"a2aApiKey",
|
|
3179
|
+
defaultA2AApiKeyStore
|
|
3180
|
+
);
|
|
2995
3181
|
|
|
2996
3182
|
// src/tool_lattice/manage_binding/index.ts
|
|
2997
3183
|
function getInstallationStore() {
|
|
@@ -7079,7 +7265,7 @@ var createBrowserGetInfoTool = ({ vmIsolation }) => {
|
|
|
7079
7265
|
};
|
|
7080
7266
|
|
|
7081
7267
|
// src/index.ts
|
|
7082
|
-
var
|
|
7268
|
+
var import_messages6 = require("@langchain/core/messages");
|
|
7083
7269
|
|
|
7084
7270
|
// src/agent_lattice/types.ts
|
|
7085
7271
|
var import_protocols = require("@axiom-lattice/protocols");
|
|
@@ -12113,6 +12299,14 @@ var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
|
|
|
12113
12299
|
return ThreadStatus3;
|
|
12114
12300
|
})(ThreadStatus2 || {});
|
|
12115
12301
|
var Agent = class {
|
|
12302
|
+
/**
|
|
12303
|
+
* Constructs an Agent instance.
|
|
12304
|
+
*
|
|
12305
|
+
* Prefer {@link AgentInstanceManager.getAgent} over direct construction — it
|
|
12306
|
+
* ensures a single instance per thread.
|
|
12307
|
+
*
|
|
12308
|
+
* @param params - {@link AgentThreadInterface}
|
|
12309
|
+
*/
|
|
12116
12310
|
constructor({
|
|
12117
12311
|
assistant_id,
|
|
12118
12312
|
thread_id,
|
|
@@ -12325,6 +12519,7 @@ var Agent = class {
|
|
|
12325
12519
|
await this.queueStore?.removeMessage(p.id);
|
|
12326
12520
|
const runStatus = await this.getRunStatus();
|
|
12327
12521
|
const state = await this.getCurrentState();
|
|
12522
|
+
const customRunConfig = p.custom_run_config ?? queueMessageData.custom_run_config;
|
|
12328
12523
|
if (runStatus === "interrupted" /* INTERRUPTED */) {
|
|
12329
12524
|
this.publish("message:interrupted", {
|
|
12330
12525
|
type: "message:interrupted",
|
|
@@ -12349,6 +12544,12 @@ var Agent = class {
|
|
|
12349
12544
|
state
|
|
12350
12545
|
});
|
|
12351
12546
|
}
|
|
12547
|
+
this.publish("reply:ready", {
|
|
12548
|
+
type: "reply:ready",
|
|
12549
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
12550
|
+
state,
|
|
12551
|
+
customRunConfig
|
|
12552
|
+
});
|
|
12352
12553
|
} catch (error) {
|
|
12353
12554
|
console.error(`STEER/Command message ${p.id} execution failed:`, error);
|
|
12354
12555
|
this.addChunk({
|
|
@@ -12427,6 +12628,12 @@ var Agent = class {
|
|
|
12427
12628
|
});
|
|
12428
12629
|
}
|
|
12429
12630
|
}
|
|
12631
|
+
this.publish("reply:ready", {
|
|
12632
|
+
type: "reply:ready",
|
|
12633
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
12634
|
+
state,
|
|
12635
|
+
customRunConfig: remainingPendings[0]?.custom_run_config ?? firstQueueMessage?.custom_run_config
|
|
12636
|
+
});
|
|
12430
12637
|
} catch (error) {
|
|
12431
12638
|
console.error(`COLLECT mode execution failed:`, error);
|
|
12432
12639
|
for (const p of remainingPendings) {
|
|
@@ -12475,6 +12682,7 @@ var Agent = class {
|
|
|
12475
12682
|
await this.queueStore?.removeMessage(p.id);
|
|
12476
12683
|
const runStatus = await this.getRunStatus();
|
|
12477
12684
|
const state = await this.getCurrentState();
|
|
12685
|
+
const customRunConfig = p.custom_run_config ?? queueMessageData.custom_run_config;
|
|
12478
12686
|
if (runStatus === "interrupted" /* INTERRUPTED */) {
|
|
12479
12687
|
this.publish("message:interrupted", {
|
|
12480
12688
|
type: "message:interrupted",
|
|
@@ -12499,6 +12707,12 @@ var Agent = class {
|
|
|
12499
12707
|
state
|
|
12500
12708
|
});
|
|
12501
12709
|
}
|
|
12710
|
+
this.publish("reply:ready", {
|
|
12711
|
+
type: "reply:ready",
|
|
12712
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
12713
|
+
state,
|
|
12714
|
+
customRunConfig
|
|
12715
|
+
});
|
|
12502
12716
|
} catch (error) {
|
|
12503
12717
|
console.error(`FOLLOWUP mode message ${p.id} execution failed:`, error);
|
|
12504
12718
|
this.addChunk({
|
|
@@ -12541,9 +12755,25 @@ var Agent = class {
|
|
|
12541
12755
|
setQueueStore(store) {
|
|
12542
12756
|
this.queueStore = store;
|
|
12543
12757
|
}
|
|
12758
|
+
/**
|
|
12759
|
+
* Push a chunk into the streaming buffer for this thread.
|
|
12760
|
+
*
|
|
12761
|
+
* Consumers read chunks via {@link chunkStream}.
|
|
12762
|
+
*
|
|
12763
|
+
* @param content - The message chunk to buffer
|
|
12764
|
+
*/
|
|
12544
12765
|
addChunk(content) {
|
|
12545
12766
|
return this.chunkBuffer.addChunk(this.thread_id, content);
|
|
12546
12767
|
}
|
|
12768
|
+
/**
|
|
12769
|
+
* Returns an async iterator over new chunks since the given message ID.
|
|
12770
|
+
*
|
|
12771
|
+
* Used by SSE endpoints to stream agent output to clients in real time.
|
|
12772
|
+
*
|
|
12773
|
+
* @param message_id - The client message ID to start streaming from
|
|
12774
|
+
* @param stopTypes - Optional chunk types that terminate the stream
|
|
12775
|
+
* @returns An async iterable yielding {@link MessageChunk} objects
|
|
12776
|
+
*/
|
|
12547
12777
|
chunkStream(message_id, stopTypes) {
|
|
12548
12778
|
const stream = this.chunkBuffer.getNewChunksSinceContentIterator(
|
|
12549
12779
|
this.thread_id,
|
|
@@ -12632,13 +12862,21 @@ var Agent = class {
|
|
|
12632
12862
|
};
|
|
12633
12863
|
}
|
|
12634
12864
|
/**
|
|
12635
|
-
*
|
|
12865
|
+
* Override the thread's queue processing mode.
|
|
12866
|
+
*
|
|
12867
|
+
* @param config - Partial {@link ThreadQueueConfig} (e.g. `{ mode: QueueMode.FOLLOWUP }`)
|
|
12636
12868
|
*/
|
|
12637
12869
|
async setQueueConfig(config) {
|
|
12638
12870
|
this.queueMode = { ...this.queueMode, ...config };
|
|
12639
12871
|
}
|
|
12640
12872
|
/**
|
|
12641
|
-
*
|
|
12873
|
+
* Abort any ongoing queue processing without clearing the queue.
|
|
12874
|
+
*
|
|
12875
|
+
* Used internally by STEER mode to interrupt the current execution so the
|
|
12876
|
+
* steer message can be processed next. For a full abort that also clears
|
|
12877
|
+
* pending messages, use {@link abort}.
|
|
12878
|
+
*
|
|
12879
|
+
* @see {@link abort}
|
|
12642
12880
|
*/
|
|
12643
12881
|
stopQueueProcessor() {
|
|
12644
12882
|
if (this.abortController) {
|
|
@@ -12647,14 +12885,34 @@ var Agent = class {
|
|
|
12647
12885
|
}
|
|
12648
12886
|
}
|
|
12649
12887
|
/**
|
|
12650
|
-
*
|
|
12651
|
-
*
|
|
12652
|
-
*
|
|
12653
|
-
*
|
|
12654
|
-
*
|
|
12655
|
-
*
|
|
12656
|
-
* -
|
|
12657
|
-
* -
|
|
12888
|
+
* Enqueue a message for this thread.
|
|
12889
|
+
*
|
|
12890
|
+
* Messages are always queued; the queue processor starts automatically if idle.
|
|
12891
|
+
* Returns immediately with the message ID — execution is asynchronous.
|
|
12892
|
+
*
|
|
12893
|
+
* **Queue modes** (via the optional `mode` param):
|
|
12894
|
+
* - `COLLECT` (default) — Batch multiple pending messages into one agent call.
|
|
12895
|
+
* - `FOLLOWUP` — Process messages one at a time in order.
|
|
12896
|
+
* - `STEER` — High-priority, inserted at queue head, interrupts current processing.
|
|
12897
|
+
*
|
|
12898
|
+
* **Format**: Supports both `input.message` (legacy string) and `input.messages[]`
|
|
12899
|
+
* (array of `{ role, content }` objects). The array form takes precedence.
|
|
12900
|
+
*
|
|
12901
|
+
* The `custom_run_config` field is round-tripped through the queue and emitted
|
|
12902
|
+
* back in {@link ReplyReadyEvent}, enabling callers to attach routing metadata
|
|
12903
|
+
* (e.g. `_replyTarget` for channel reply).
|
|
12904
|
+
*
|
|
12905
|
+
* @param queueMessage - The message to enqueue
|
|
12906
|
+
* @param mode - Optional queue mode override (defaults to thread's current mode)
|
|
12907
|
+
* @returns `{ queued: true, executed: false, messageId }` — execution happens asynchronously
|
|
12908
|
+
*
|
|
12909
|
+
* @example
|
|
12910
|
+
* ```ts
|
|
12911
|
+
* await agent.addMessage({
|
|
12912
|
+
* input: { message: "Hello" },
|
|
12913
|
+
* custom_run_config: { _replyTarget: { adapterChannel: "lark", rawTarget: { chatId: "xxx" } } },
|
|
12914
|
+
* });
|
|
12915
|
+
* ```
|
|
12658
12916
|
*/
|
|
12659
12917
|
async addMessage(queueMessage, mode) {
|
|
12660
12918
|
const useMode = mode ?? this.queueMode.mode;
|
|
@@ -12748,8 +13006,13 @@ var Agent = class {
|
|
|
12748
13006
|
return { queued: true, executed: false, messageId };
|
|
12749
13007
|
}
|
|
12750
13008
|
/**
|
|
12751
|
-
* Start queue processor if not already running
|
|
12752
|
-
*
|
|
13009
|
+
* Start the queue processor if it is not already running.
|
|
13010
|
+
*
|
|
13011
|
+
* Called automatically by {@link addMessage} and {@link resumeTask}.
|
|
13012
|
+
* Safe to call externally — it is a no-op if processing is already active.
|
|
13013
|
+
*
|
|
13014
|
+
* Emits `thread:busy` before starting, and starts the {@link waitingForQueueEnd}
|
|
13015
|
+
* loop with a fresh {@link AbortController}.
|
|
12753
13016
|
*/
|
|
12754
13017
|
async startQueueProcessorIfNeeded() {
|
|
12755
13018
|
const store = this.getQueueStore();
|
|
@@ -12797,6 +13060,12 @@ var Agent = class {
|
|
|
12797
13060
|
type: "system"
|
|
12798
13061
|
});
|
|
12799
13062
|
}
|
|
13063
|
+
/**
|
|
13064
|
+
* Returns a LangGraph StateSnapshot for this thread.
|
|
13065
|
+
*
|
|
13066
|
+
* Includes `state.values.messages` (full conversation history) and
|
|
13067
|
+
* `state.tasks` / `state.next` (execution progress).
|
|
13068
|
+
*/
|
|
12800
13069
|
async getCurrentState() {
|
|
12801
13070
|
const { runnable_agent } = await this.getLatticeClientAndRuntimeConfig();
|
|
12802
13071
|
const state = await runnable_agent.getState({
|
|
@@ -12804,6 +13073,14 @@ var Agent = class {
|
|
|
12804
13073
|
});
|
|
12805
13074
|
return state;
|
|
12806
13075
|
}
|
|
13076
|
+
/**
|
|
13077
|
+
* Returns the conversation history as normalized message objects.
|
|
13078
|
+
*
|
|
13079
|
+
* Filters to `human`, `ai`, and `tool` message types. Each entry has
|
|
13080
|
+
* `{ id, role, content }` plus any LangChain kwargs.
|
|
13081
|
+
*
|
|
13082
|
+
* @returns Array of message objects with `id`, `role`, and `content`
|
|
13083
|
+
*/
|
|
12807
13084
|
async getCurrentMessages() {
|
|
12808
13085
|
const state = await this.getCurrentState();
|
|
12809
13086
|
const messages = state.values.messages || [];
|
|
@@ -12826,6 +13103,14 @@ var Agent = class {
|
|
|
12826
13103
|
const image = await drawableGraph.drawMermaid();
|
|
12827
13104
|
return image;
|
|
12828
13105
|
}
|
|
13106
|
+
/**
|
|
13107
|
+
* Determine the current thread execution status.
|
|
13108
|
+
*
|
|
13109
|
+
* Checks LangGraph's `state.tasks` for interrupts and `state.next` for
|
|
13110
|
+
* pending steps.
|
|
13111
|
+
*
|
|
13112
|
+
* @returns {@link ThreadStatus} — `IDLE`, `BUSY`, or `INTERRUPTED`
|
|
13113
|
+
*/
|
|
12829
13114
|
async getRunStatus() {
|
|
12830
13115
|
const state = await this.getCurrentState();
|
|
12831
13116
|
const isInterrupted = state.tasks?.some(
|
|
@@ -12840,9 +13125,14 @@ var Agent = class {
|
|
|
12840
13125
|
return "idle" /* IDLE */;
|
|
12841
13126
|
}
|
|
12842
13127
|
/**
|
|
12843
|
-
* Resume
|
|
12844
|
-
*
|
|
12845
|
-
*
|
|
13128
|
+
* Resume processing after a server restart.
|
|
13129
|
+
*
|
|
13130
|
+
* Resets any stuck "processing" messages back to "pending" and restarts the
|
|
13131
|
+
* queue processor. Skips threads that are in `INTERRUPTED` state (the
|
|
13132
|
+
* interruption was intentional).
|
|
13133
|
+
*
|
|
13134
|
+
* Called during gateway startup to recover threads that were mid-execution
|
|
13135
|
+
* when the server went down.
|
|
12846
13136
|
*/
|
|
12847
13137
|
async resumeTask() {
|
|
12848
13138
|
try {
|
|
@@ -12864,9 +13154,14 @@ var Agent = class {
|
|
|
12864
13154
|
await this.startQueueProcessorIfNeeded();
|
|
12865
13155
|
}
|
|
12866
13156
|
/**
|
|
12867
|
-
*
|
|
12868
|
-
*
|
|
12869
|
-
*
|
|
13157
|
+
* Fully abort all activity on this thread.
|
|
13158
|
+
*
|
|
13159
|
+
* Aborts any in-flight agent execution (via {@link AbortController}) and
|
|
13160
|
+
* clears all pending and processing messages from the queue. Also marks
|
|
13161
|
+
* the chunk buffer thread as aborted so streaming consumers can detect it.
|
|
13162
|
+
*
|
|
13163
|
+
* Unlike {@link stopQueueProcessor}, this is a destructive abort — the
|
|
13164
|
+
* queue is drained.
|
|
12870
13165
|
*/
|
|
12871
13166
|
async abort() {
|
|
12872
13167
|
if (this.abortController) {
|
|
@@ -12884,22 +13179,44 @@ var Agent = class {
|
|
|
12884
13179
|
return this.abortController?.signal.aborted ?? false;
|
|
12885
13180
|
}
|
|
12886
13181
|
/**
|
|
12887
|
-
* Subscribe to lifecycle
|
|
12888
|
-
*
|
|
13182
|
+
* Subscribe to a lifecycle event for this specific thread.
|
|
13183
|
+
*
|
|
13184
|
+
* Event names are namespaced as `{eventName}:{tenantId}:{threadId}` so
|
|
13185
|
+
* listeners only receive events for this agent instance.
|
|
13186
|
+
*
|
|
13187
|
+
* @param eventName - One of {@link AgentLifecycleEventName}
|
|
13188
|
+
* @param callback - Handler receiving the event data payload
|
|
13189
|
+
*
|
|
13190
|
+
* @example
|
|
13191
|
+
* ```ts
|
|
13192
|
+
* agent.subscribe("message:completed", (evt) => {
|
|
13193
|
+
* console.log("AI response:", evt.state?.values?.messages);
|
|
13194
|
+
* });
|
|
13195
|
+
* ```
|
|
12889
13196
|
*/
|
|
12890
13197
|
subscribe(eventName, callback) {
|
|
12891
13198
|
const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
|
|
12892
13199
|
event_bus_default.subscribe(namespacedEvent, callback);
|
|
12893
13200
|
}
|
|
12894
13201
|
/**
|
|
12895
|
-
*
|
|
13202
|
+
* Remove a previously registered event listener.
|
|
13203
|
+
*
|
|
13204
|
+
* @param eventName - The event that was subscribed to
|
|
13205
|
+
* @param callback - The same function reference used in {@link subscribe}
|
|
12896
13206
|
*/
|
|
12897
13207
|
unsubscribe(eventName, callback) {
|
|
12898
13208
|
const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
|
|
12899
13209
|
event_bus_default.unsubscribe(namespacedEvent, callback);
|
|
12900
13210
|
}
|
|
12901
13211
|
/**
|
|
12902
|
-
* Subscribe to lifecycle
|
|
13212
|
+
* Subscribe to a lifecycle event once — the listener is removed after the
|
|
13213
|
+
* first invocation.
|
|
13214
|
+
*
|
|
13215
|
+
* Ideal for one-shot async patterns (e.g. waiting for `reply:ready` before
|
|
13216
|
+
* sending a channel reply).
|
|
13217
|
+
*
|
|
13218
|
+
* @param eventName - One of {@link AgentLifecycleEventName}
|
|
13219
|
+
* @param callback - Handler receiving the event data payload
|
|
12903
13220
|
*/
|
|
12904
13221
|
subscribeOnce(eventName, callback) {
|
|
12905
13222
|
const namespacedEvent = `${eventName}:${this.tenant_id}:${this.thread_id}`;
|
|
@@ -12913,6 +13230,12 @@ var Agent = class {
|
|
|
12913
13230
|
console.log(namespacedEvent);
|
|
12914
13231
|
event_bus_default.publish(namespacedEvent, data);
|
|
12915
13232
|
}
|
|
13233
|
+
/**
|
|
13234
|
+
* Track a sub-agent async task spawned by this agent.
|
|
13235
|
+
*
|
|
13236
|
+
* Tasks are monitored by the agent task consumer in `packages/gateway`
|
|
13237
|
+
* and their status can be polled via {@link getAsyncTasks}.
|
|
13238
|
+
*/
|
|
12916
13239
|
addAsyncTask(task) {
|
|
12917
13240
|
this.asyncTasks.push(task);
|
|
12918
13241
|
}
|
|
@@ -12922,6 +13245,12 @@ var Agent = class {
|
|
|
12922
13245
|
getAsyncTask(taskId) {
|
|
12923
13246
|
return this.asyncTasks.find((t) => t.taskId === taskId);
|
|
12924
13247
|
}
|
|
13248
|
+
/**
|
|
13249
|
+
* Update the status of a tracked async task.
|
|
13250
|
+
*
|
|
13251
|
+
* Terminal states (`completed`, `failed`, `cancelled`) automatically
|
|
13252
|
+
* set `completedAt` to the current timestamp.
|
|
13253
|
+
*/
|
|
12925
13254
|
updateAsyncTaskStatus(taskId, status) {
|
|
12926
13255
|
const task = this.getAsyncTask(taskId);
|
|
12927
13256
|
if (!task) return;
|
|
@@ -13287,6 +13616,65 @@ function createSchedulerMiddleware(options = {}) {
|
|
|
13287
13616
|
});
|
|
13288
13617
|
}
|
|
13289
13618
|
|
|
13619
|
+
// src/agent_lattice/builders/CustomMiddlewareRegistry.ts
|
|
13620
|
+
var CustomMiddlewareRegistry = class {
|
|
13621
|
+
/**
|
|
13622
|
+
* Register a custom middleware factory under the given key.
|
|
13623
|
+
*
|
|
13624
|
+
* The key is referenced by `config.key` in the database middleware configuration.
|
|
13625
|
+
* When an agent is built, the framework looks up this key and calls the factory
|
|
13626
|
+
* with the remaining config fields.
|
|
13627
|
+
*
|
|
13628
|
+
* @param key - Unique identifier, referenced in database config as `config.key`
|
|
13629
|
+
* @param factory - Function that receives config (minus `key`) and returns an AgentMiddleware
|
|
13630
|
+
*
|
|
13631
|
+
* @example
|
|
13632
|
+
* ```ts
|
|
13633
|
+
* CustomMiddlewareRegistry.register("my-logger", (config) =>
|
|
13634
|
+
* createMiddleware({ name: "Logger", beforeAgent: async () => { ... } }),
|
|
13635
|
+
* );
|
|
13636
|
+
* ```
|
|
13637
|
+
*/
|
|
13638
|
+
static register(key, factory) {
|
|
13639
|
+
this.factories.set(key, factory);
|
|
13640
|
+
}
|
|
13641
|
+
/**
|
|
13642
|
+
* Remove a previously registered factory.
|
|
13643
|
+
*
|
|
13644
|
+
* @param key - The factory key to unregister
|
|
13645
|
+
* @returns `true` if a factory was removed, `false` if the key was not found
|
|
13646
|
+
*/
|
|
13647
|
+
static unregister(key) {
|
|
13648
|
+
return this.factories.delete(key);
|
|
13649
|
+
}
|
|
13650
|
+
/**
|
|
13651
|
+
* Look up a factory by key.
|
|
13652
|
+
*
|
|
13653
|
+
* @param key - The factory key
|
|
13654
|
+
* @returns The factory function, or `undefined` if not registered
|
|
13655
|
+
*/
|
|
13656
|
+
static get(key) {
|
|
13657
|
+
return this.factories.get(key);
|
|
13658
|
+
}
|
|
13659
|
+
/**
|
|
13660
|
+
* Check whether a factory is registered under the given key.
|
|
13661
|
+
*
|
|
13662
|
+
* @param key - The factory key to check
|
|
13663
|
+
*/
|
|
13664
|
+
static has(key) {
|
|
13665
|
+
return this.factories.has(key);
|
|
13666
|
+
}
|
|
13667
|
+
/**
|
|
13668
|
+
* Get all currently registered factory keys.
|
|
13669
|
+
*
|
|
13670
|
+
* @returns Array of registered key strings
|
|
13671
|
+
*/
|
|
13672
|
+
static list() {
|
|
13673
|
+
return Array.from(this.factories.keys());
|
|
13674
|
+
}
|
|
13675
|
+
};
|
|
13676
|
+
CustomMiddlewareRegistry.factories = /* @__PURE__ */ new Map();
|
|
13677
|
+
|
|
13290
13678
|
// src/agent_lattice/builders/commonMiddleware.ts
|
|
13291
13679
|
async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsIsExised) {
|
|
13292
13680
|
const middlewares = [];
|
|
@@ -13363,6 +13751,21 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
|
|
|
13363
13751
|
case "scheduler":
|
|
13364
13752
|
middlewares.push(createSchedulerMiddleware(config.config));
|
|
13365
13753
|
break;
|
|
13754
|
+
case "custom":
|
|
13755
|
+
{
|
|
13756
|
+
const customConfig = config.config;
|
|
13757
|
+
const { key, ...rest } = customConfig;
|
|
13758
|
+
const factory = CustomMiddlewareRegistry.get(key);
|
|
13759
|
+
if (factory) {
|
|
13760
|
+
const middleware = factory(rest);
|
|
13761
|
+
middlewares.push(middleware instanceof Promise ? await middleware : middleware);
|
|
13762
|
+
} else {
|
|
13763
|
+
console.warn(
|
|
13764
|
+
`[custom middleware] No factory registered for key "${key}". Use CustomMiddlewareRegistry.register("${key}", factory) before building the agent.`
|
|
13765
|
+
);
|
|
13766
|
+
}
|
|
13767
|
+
}
|
|
13768
|
+
break;
|
|
13366
13769
|
}
|
|
13367
13770
|
}
|
|
13368
13771
|
return middlewares;
|
|
@@ -17969,6 +18372,227 @@ var ProcessingAgentGraphBuilder = class {
|
|
|
17969
18372
|
}
|
|
17970
18373
|
};
|
|
17971
18374
|
|
|
18375
|
+
// src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
|
|
18376
|
+
var import_langgraph14 = require("@langchain/langgraph");
|
|
18377
|
+
var import_messages5 = require("@langchain/core/messages");
|
|
18378
|
+
|
|
18379
|
+
// src/services/a2a-client.ts
|
|
18380
|
+
var import_uuid4 = require("uuid");
|
|
18381
|
+
var A2ARemoteError = class extends Error {
|
|
18382
|
+
constructor(message, statusCode, body) {
|
|
18383
|
+
super(message);
|
|
18384
|
+
this.statusCode = statusCode;
|
|
18385
|
+
this.body = body;
|
|
18386
|
+
this.name = "A2ARemoteError";
|
|
18387
|
+
}
|
|
18388
|
+
};
|
|
18389
|
+
var A2ARemoteClient = class {
|
|
18390
|
+
constructor(config) {
|
|
18391
|
+
this.config = config;
|
|
18392
|
+
this.jsonRpcUrl = null;
|
|
18393
|
+
this.card = null;
|
|
18394
|
+
}
|
|
18395
|
+
// ── Resolution ───────────────────────────────────────────────────────────
|
|
18396
|
+
/**
|
|
18397
|
+
* Fetch the agent card and resolve the JSON-RPC endpoint.
|
|
18398
|
+
*/
|
|
18399
|
+
async resolve() {
|
|
18400
|
+
if (this.card) return this.card;
|
|
18401
|
+
const resp = await fetch(this.config.agentCardUrl, {
|
|
18402
|
+
signal: AbortSignal.timeout(this.config.timeout ?? 3e4)
|
|
18403
|
+
});
|
|
18404
|
+
if (!resp.ok) {
|
|
18405
|
+
throw new A2ARemoteError(
|
|
18406
|
+
`Failed to fetch agent card: HTTP ${resp.status}`,
|
|
18407
|
+
resp.status
|
|
18408
|
+
);
|
|
18409
|
+
}
|
|
18410
|
+
this.card = await resp.json();
|
|
18411
|
+
const card = this.card;
|
|
18412
|
+
const jsonRpc = card.additionalInterfaces?.find(
|
|
18413
|
+
(i) => i.transport === "JSONRPC"
|
|
18414
|
+
);
|
|
18415
|
+
this.jsonRpcUrl = jsonRpc?.url ?? card.url;
|
|
18416
|
+
return this.card;
|
|
18417
|
+
}
|
|
18418
|
+
// ── Execute ──────────────────────────────────────────────────────────────
|
|
18419
|
+
/**
|
|
18420
|
+
* Send a text prompt to the remote A2A agent and return the response.
|
|
18421
|
+
*
|
|
18422
|
+
* Supports SSE streaming (parses status-update events) and falls back
|
|
18423
|
+
* to polling the task status for non-streaming agents.
|
|
18424
|
+
*/
|
|
18425
|
+
async sendMessage(text) {
|
|
18426
|
+
await this.resolve();
|
|
18427
|
+
const taskId = (0, import_uuid4.v4)();
|
|
18428
|
+
const body = JSON.stringify({
|
|
18429
|
+
jsonrpc: "2.0",
|
|
18430
|
+
method: "tasks/send",
|
|
18431
|
+
params: {
|
|
18432
|
+
id: taskId,
|
|
18433
|
+
message: {
|
|
18434
|
+
role: "user",
|
|
18435
|
+
parts: [{ kind: "text", text }]
|
|
18436
|
+
}
|
|
18437
|
+
},
|
|
18438
|
+
id: taskId
|
|
18439
|
+
});
|
|
18440
|
+
const headers = {
|
|
18441
|
+
"Content-Type": "application/json",
|
|
18442
|
+
"Accept": "text/event-stream"
|
|
18443
|
+
};
|
|
18444
|
+
if (this.config.apiKey) {
|
|
18445
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
18446
|
+
}
|
|
18447
|
+
const resp = await fetch(this.jsonRpcUrl, {
|
|
18448
|
+
method: "POST",
|
|
18449
|
+
headers,
|
|
18450
|
+
body,
|
|
18451
|
+
signal: AbortSignal.timeout(this.config.timeout ?? 3e5)
|
|
18452
|
+
});
|
|
18453
|
+
if (!resp.ok) {
|
|
18454
|
+
const text2 = await resp.text().catch(() => "");
|
|
18455
|
+
throw new A2ARemoteError(
|
|
18456
|
+
`A2A request failed: HTTP ${resp.status}`,
|
|
18457
|
+
resp.status,
|
|
18458
|
+
text2
|
|
18459
|
+
);
|
|
18460
|
+
}
|
|
18461
|
+
const contentType = resp.headers.get("content-type") ?? "";
|
|
18462
|
+
if (contentType.includes("text/event-stream")) {
|
|
18463
|
+
return this.parseSSE(resp);
|
|
18464
|
+
}
|
|
18465
|
+
const json = await resp.json();
|
|
18466
|
+
return this.extractArtifactText(json);
|
|
18467
|
+
}
|
|
18468
|
+
// ── SSE Parsing ──────────────────────────────────────────────────────────
|
|
18469
|
+
async parseSSE(resp) {
|
|
18470
|
+
if (!resp.body) {
|
|
18471
|
+
throw new A2ARemoteError("Empty response body");
|
|
18472
|
+
}
|
|
18473
|
+
const reader = resp.body.getReader();
|
|
18474
|
+
const decoder = new TextDecoder();
|
|
18475
|
+
let buffer2 = "";
|
|
18476
|
+
let accumulatedText = "";
|
|
18477
|
+
try {
|
|
18478
|
+
while (true) {
|
|
18479
|
+
const { done, value } = await reader.read();
|
|
18480
|
+
if (done) break;
|
|
18481
|
+
buffer2 += decoder.decode(value, { stream: true });
|
|
18482
|
+
const lines = buffer2.split("\n");
|
|
18483
|
+
buffer2 = lines.pop() ?? "";
|
|
18484
|
+
for (const line of lines) {
|
|
18485
|
+
if (line.startsWith("data: ")) {
|
|
18486
|
+
const data = line.slice(6).trim();
|
|
18487
|
+
if (!data) continue;
|
|
18488
|
+
try {
|
|
18489
|
+
const event = JSON.parse(data);
|
|
18490
|
+
this.handleSSEEvent(event, (t) => {
|
|
18491
|
+
accumulatedText += t;
|
|
18492
|
+
});
|
|
18493
|
+
} catch {
|
|
18494
|
+
}
|
|
18495
|
+
}
|
|
18496
|
+
}
|
|
18497
|
+
}
|
|
18498
|
+
if (buffer2.startsWith("data: ")) {
|
|
18499
|
+
const data = buffer2.slice(6).trim();
|
|
18500
|
+
if (data) {
|
|
18501
|
+
try {
|
|
18502
|
+
const event = JSON.parse(data);
|
|
18503
|
+
this.handleSSEEvent(event, (t) => {
|
|
18504
|
+
accumulatedText += t;
|
|
18505
|
+
});
|
|
18506
|
+
} catch {
|
|
18507
|
+
}
|
|
18508
|
+
}
|
|
18509
|
+
}
|
|
18510
|
+
} finally {
|
|
18511
|
+
reader.releaseLock();
|
|
18512
|
+
}
|
|
18513
|
+
return accumulatedText;
|
|
18514
|
+
}
|
|
18515
|
+
handleSSEEvent(event, onText) {
|
|
18516
|
+
const e = event;
|
|
18517
|
+
const messageParts = e.status?.message?.parts;
|
|
18518
|
+
if (messageParts) {
|
|
18519
|
+
for (const part of messageParts) {
|
|
18520
|
+
if (part.text) onText(part.text);
|
|
18521
|
+
}
|
|
18522
|
+
}
|
|
18523
|
+
}
|
|
18524
|
+
// ── Artifact Extraction ──────────────────────────────────────────────────
|
|
18525
|
+
extractArtifactText(task) {
|
|
18526
|
+
const artifacts = task.artifacts ?? [];
|
|
18527
|
+
return artifacts.flatMap((a) => a.parts ?? []).filter((p) => p.text).map((p) => p.text).join("\n");
|
|
18528
|
+
}
|
|
18529
|
+
};
|
|
18530
|
+
|
|
18531
|
+
// src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
|
|
18532
|
+
var import_protocols9 = require("@axiom-lattice/protocols");
|
|
18533
|
+
var RemoteAgentGraphBuilder = class {
|
|
18534
|
+
async build(agentLattice, params) {
|
|
18535
|
+
if (agentLattice.config.type !== import_protocols9.AgentType.A2A_REMOTE) {
|
|
18536
|
+
throw new Error(
|
|
18537
|
+
`RemoteAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
|
|
18538
|
+
);
|
|
18539
|
+
}
|
|
18540
|
+
const config = agentLattice.config;
|
|
18541
|
+
const client = new A2ARemoteClient({
|
|
18542
|
+
agentCardUrl: config.agentCardUrl,
|
|
18543
|
+
apiKey: config.apiKey,
|
|
18544
|
+
timeout: config.timeout
|
|
18545
|
+
});
|
|
18546
|
+
await client.resolve();
|
|
18547
|
+
const remoteCallNode = async (state) => {
|
|
18548
|
+
const messages = state.messages ?? [];
|
|
18549
|
+
const text = extractLastHumanMessage(messages);
|
|
18550
|
+
if (!text) {
|
|
18551
|
+
return {
|
|
18552
|
+
messages: [
|
|
18553
|
+
new import_messages5.AIMessage("No text input provided to remote agent.")
|
|
18554
|
+
]
|
|
18555
|
+
};
|
|
18556
|
+
}
|
|
18557
|
+
try {
|
|
18558
|
+
const fullPrompt = params.prompt ? `${params.prompt}
|
|
18559
|
+
|
|
18560
|
+
User request:
|
|
18561
|
+
${text}` : text;
|
|
18562
|
+
const response = await client.sendMessage(fullPrompt);
|
|
18563
|
+
return {
|
|
18564
|
+
messages: [new import_messages5.AIMessage(response)]
|
|
18565
|
+
};
|
|
18566
|
+
} catch (error) {
|
|
18567
|
+
const msg = error.message ?? String(error);
|
|
18568
|
+
return {
|
|
18569
|
+
messages: [
|
|
18570
|
+
new import_messages5.AIMessage(`Remote A2A agent error: ${msg}`)
|
|
18571
|
+
]
|
|
18572
|
+
};
|
|
18573
|
+
}
|
|
18574
|
+
};
|
|
18575
|
+
const workflow = new import_langgraph14.StateGraph(import_langgraph14.MessagesAnnotation).addNode("remote_call", remoteCallNode).addEdge("__start__", "remote_call").addEdge("remote_call", "__end__");
|
|
18576
|
+
return workflow.compile();
|
|
18577
|
+
}
|
|
18578
|
+
};
|
|
18579
|
+
function extractLastHumanMessage(messages) {
|
|
18580
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
18581
|
+
const msg = messages[i];
|
|
18582
|
+
if (msg._getType() === "human") {
|
|
18583
|
+
const content = msg.content;
|
|
18584
|
+
if (typeof content === "string") return content;
|
|
18585
|
+
if (Array.isArray(content)) {
|
|
18586
|
+
return content.filter(
|
|
18587
|
+
(c) => typeof c === "object" && c !== null && c.type === "text"
|
|
18588
|
+
).map((c) => c.text).join("\n");
|
|
18589
|
+
}
|
|
18590
|
+
return String(content);
|
|
18591
|
+
}
|
|
18592
|
+
}
|
|
18593
|
+
return "";
|
|
18594
|
+
}
|
|
18595
|
+
|
|
17972
18596
|
// src/agent_lattice/builders/AgentGraphBuilderFactory.ts
|
|
17973
18597
|
var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
|
|
17974
18598
|
constructor() {
|
|
@@ -17992,6 +18616,7 @@ var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
|
|
|
17992
18616
|
this.builders.set(import_protocols.AgentType.DEEP_AGENT, new DeepAgentGraphBuilder());
|
|
17993
18617
|
this.builders.set(import_protocols.AgentType.TEAM, new TeamAgentGraphBuilder());
|
|
17994
18618
|
this.builders.set(import_protocols.AgentType.PROCESSING, new ProcessingAgentGraphBuilder());
|
|
18619
|
+
this.builders.set(import_protocols.AgentType.A2A_REMOTE, new RemoteAgentGraphBuilder());
|
|
17995
18620
|
}
|
|
17996
18621
|
/**
|
|
17997
18622
|
* 注册自定义Builder
|
|
@@ -18018,7 +18643,7 @@ var AgentGraphBuilderFactory = class _AgentGraphBuilderFactory {
|
|
|
18018
18643
|
};
|
|
18019
18644
|
|
|
18020
18645
|
// src/agent_lattice/builders/AgentParamsBuilder.ts
|
|
18021
|
-
var
|
|
18646
|
+
var import_protocols10 = require("@axiom-lattice/protocols");
|
|
18022
18647
|
var AgentParamsBuilder = class {
|
|
18023
18648
|
/**
|
|
18024
18649
|
* constructor
|
|
@@ -18036,8 +18661,8 @@ var AgentParamsBuilder = class {
|
|
|
18036
18661
|
* @returns Agent build parameters
|
|
18037
18662
|
*/
|
|
18038
18663
|
async buildParams(agentLattice, options) {
|
|
18039
|
-
const skills = (0,
|
|
18040
|
-
const toolKeys = options?.overrideTools || (0,
|
|
18664
|
+
const skills = (0, import_protocols10.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols10.isProcessingAgentConfig)(agentLattice.config) ? agentLattice.config.skillCategories : void 0;
|
|
18665
|
+
const toolKeys = options?.overrideTools || (0, import_protocols10.getToolsFromConfig)(agentLattice.config);
|
|
18041
18666
|
const tools = toolKeys.map((toolKey) => {
|
|
18042
18667
|
const toolLattice = toolLatticeManager.getToolLattice(toolKey);
|
|
18043
18668
|
if (!toolLattice) {
|
|
@@ -18054,7 +18679,7 @@ var AgentParamsBuilder = class {
|
|
|
18054
18679
|
if (!model) {
|
|
18055
18680
|
throw new Error(`Model "${modelKey}" does not exist`);
|
|
18056
18681
|
}
|
|
18057
|
-
const subAgentKeys = (0,
|
|
18682
|
+
const subAgentKeys = (0, import_protocols10.getSubAgentsFromConfig)(agentLattice.config);
|
|
18058
18683
|
const subAgents = await Promise.all(subAgentKeys.map(async (agentKey) => {
|
|
18059
18684
|
const subAgentLattice = await this.getAgentLatticeFunc(agentKey);
|
|
18060
18685
|
if (!subAgentLattice) {
|
|
@@ -18067,7 +18692,7 @@ var AgentParamsBuilder = class {
|
|
|
18067
18692
|
};
|
|
18068
18693
|
}));
|
|
18069
18694
|
let internalSubAgents = [];
|
|
18070
|
-
if ((0,
|
|
18695
|
+
if ((0, import_protocols10.isDeepAgentConfig)(agentLattice.config) || (0, import_protocols10.isProcessingAgentConfig)(agentLattice.config)) {
|
|
18071
18696
|
internalSubAgents = agentLattice.config.internalSubAgents?.map((i) => ({
|
|
18072
18697
|
key: i.key,
|
|
18073
18698
|
config: i
|
|
@@ -18663,8 +19288,8 @@ ${body}` : `${frontmatter}
|
|
|
18663
19288
|
|
|
18664
19289
|
// src/agent_lattice/agentArchitectTools.ts
|
|
18665
19290
|
var import_zod53 = __toESM(require("zod"));
|
|
18666
|
-
var
|
|
18667
|
-
var
|
|
19291
|
+
var import_uuid5 = require("uuid");
|
|
19292
|
+
var import_protocols11 = require("@axiom-lattice/protocols");
|
|
18668
19293
|
function getTenantId(exeConfig) {
|
|
18669
19294
|
const runConfig = exeConfig?.configurable?.runConfig || {};
|
|
18670
19295
|
return runConfig.tenantId || "default";
|
|
@@ -18772,7 +19397,7 @@ registerToolLattice(
|
|
|
18772
19397
|
key: id,
|
|
18773
19398
|
name: input.name,
|
|
18774
19399
|
description: input.description || "",
|
|
18775
|
-
type: input.type === "deep_agent" ?
|
|
19400
|
+
type: input.type === "deep_agent" ? import_protocols11.AgentType.DEEP_AGENT : import_protocols11.AgentType.REACT,
|
|
18776
19401
|
prompt: input.prompt,
|
|
18777
19402
|
...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
|
|
18778
19403
|
...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
|
|
@@ -18861,7 +19486,7 @@ registerToolLattice(
|
|
|
18861
19486
|
key: id,
|
|
18862
19487
|
name: input.name,
|
|
18863
19488
|
description: input.description || "",
|
|
18864
|
-
type:
|
|
19489
|
+
type: import_protocols11.AgentType.PROCESSING,
|
|
18865
19490
|
prompt: input.prompt,
|
|
18866
19491
|
...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
|
|
18867
19492
|
middleware,
|
|
@@ -18929,7 +19554,7 @@ registerToolLattice(
|
|
|
18929
19554
|
return JSON.stringify({ error: `Agent '${input.id}' not found` });
|
|
18930
19555
|
}
|
|
18931
19556
|
const existingConfig = existing.graphDefinition || {};
|
|
18932
|
-
if (existingConfig.type !==
|
|
19557
|
+
if (existingConfig.type !== import_protocols11.AgentType.PROCESSING) {
|
|
18933
19558
|
return JSON.stringify({ error: `Agent '${input.id}' is not a PROCESSING agent (type: ${existingConfig.type})` });
|
|
18934
19559
|
}
|
|
18935
19560
|
const normalize = (s) => s.toLowerCase().replace(/[_\-\s]/g, "");
|
|
@@ -19137,7 +19762,7 @@ registerToolLattice(
|
|
|
19137
19762
|
if (!existing) {
|
|
19138
19763
|
return JSON.stringify({ error: `Agent '${id}' not found` });
|
|
19139
19764
|
}
|
|
19140
|
-
const threadId = (0,
|
|
19765
|
+
const threadId = (0, import_uuid5.v4)();
|
|
19141
19766
|
const agent = new Agent({
|
|
19142
19767
|
tenant_id: tenantId,
|
|
19143
19768
|
assistant_id: id,
|
|
@@ -19161,7 +19786,7 @@ registerToolLattice(
|
|
|
19161
19786
|
);
|
|
19162
19787
|
|
|
19163
19788
|
// src/agent_lattice/agentArchitectConfig.ts
|
|
19164
|
-
var
|
|
19789
|
+
var import_protocols13 = require("@axiom-lattice/protocols");
|
|
19165
19790
|
|
|
19166
19791
|
// src/agent_lattice/agentArchitectPrompt.ts
|
|
19167
19792
|
var AGENT_ARCHITECT_PROMPT = `# Agent Architect
|
|
@@ -19801,7 +20426,7 @@ Updates a PROCESSING agent's topology edges, name, prompt, or sub-agents. Unlike
|
|
|
19801
20426
|
`;
|
|
19802
20427
|
|
|
19803
20428
|
// src/agent_lattice/agentReviewerConfig.ts
|
|
19804
|
-
var
|
|
20429
|
+
var import_protocols12 = require("@axiom-lattice/protocols");
|
|
19805
20430
|
|
|
19806
20431
|
// src/agent_lattice/agentReviewerPrompt.ts
|
|
19807
20432
|
var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
|
|
@@ -19864,7 +20489,7 @@ var agentReviewerConfig = {
|
|
|
19864
20489
|
key: AGENT_REVIEWER_KEY,
|
|
19865
20490
|
name: "Agent Reviewer",
|
|
19866
20491
|
description: "Review and test AI agents. Use this agent to check agent configurations for correctness and to test agents by invoking them with realistic messages.",
|
|
19867
|
-
type:
|
|
20492
|
+
type: import_protocols12.AgentType.REACT,
|
|
19868
20493
|
prompt: AGENT_REVIEWER_PROMPT,
|
|
19869
20494
|
tools: [
|
|
19870
20495
|
"invoke_agent",
|
|
@@ -19890,7 +20515,7 @@ var agentArchitectConfig = {
|
|
|
19890
20515
|
key: AGENT_ARCHITECT_KEY,
|
|
19891
20516
|
name: "Agent Architect",
|
|
19892
20517
|
description: "Design and manage AI agents through natural language conversation. Use this agent when you want to create a new agent, modify an existing agent, or manage your agent collection (list, view, update, delete).",
|
|
19893
|
-
type:
|
|
20518
|
+
type: import_protocols13.AgentType.DEEP_AGENT,
|
|
19894
20519
|
prompt: AGENT_ARCHITECT_PROMPT,
|
|
19895
20520
|
tools: [
|
|
19896
20521
|
"list_agents",
|
|
@@ -20556,7 +21181,7 @@ var getVectorStoreLattice = (key) => vectorStoreLatticeManager.getVectorStoreLat
|
|
|
20556
21181
|
var getVectorStoreClient = (key) => vectorStoreLatticeManager.getVectorStoreClient(key);
|
|
20557
21182
|
|
|
20558
21183
|
// src/logger_lattice/LoggerLatticeManager.ts
|
|
20559
|
-
var
|
|
21184
|
+
var import_protocols14 = require("@axiom-lattice/protocols");
|
|
20560
21185
|
|
|
20561
21186
|
// src/logger_lattice/PinoLoggerClient.ts
|
|
20562
21187
|
var import_pino = __toESM(require("pino"));
|
|
@@ -20778,11 +21403,11 @@ var LoggerLatticeManager = class _LoggerLatticeManager extends BaseLatticeManage
|
|
|
20778
21403
|
if (client) {
|
|
20779
21404
|
loggerClient = client;
|
|
20780
21405
|
} else {
|
|
20781
|
-
if (config.type ===
|
|
21406
|
+
if (config.type === import_protocols14.LoggerType.PINO) {
|
|
20782
21407
|
loggerClient = new PinoLoggerClient(config);
|
|
20783
|
-
} else if (config.type ===
|
|
21408
|
+
} else if (config.type === import_protocols14.LoggerType.CONSOLE) {
|
|
20784
21409
|
loggerClient = new ConsoleLoggerClient(config);
|
|
20785
|
-
} else if (config.type ===
|
|
21410
|
+
} else if (config.type === import_protocols14.LoggerType.CUSTOM) {
|
|
20786
21411
|
throw new Error(
|
|
20787
21412
|
`Custom logger client must be provided. Please pass the client to registerLattice.`
|
|
20788
21413
|
);
|
|
@@ -22632,7 +23257,7 @@ function createSandboxProvider(config) {
|
|
|
22632
23257
|
var Protocols = __toESM(require("@axiom-lattice/protocols"));
|
|
22633
23258
|
|
|
22634
23259
|
// src/util/encryption.ts
|
|
22635
|
-
var
|
|
23260
|
+
var import_crypto3 = require("crypto");
|
|
22636
23261
|
var ALGORITHM = "aes-256-gcm";
|
|
22637
23262
|
var IV_LENGTH = 16;
|
|
22638
23263
|
var SALT_LENGTH = 32;
|
|
@@ -22645,7 +23270,7 @@ function getEncryptionKey() {
|
|
|
22645
23270
|
return cachedKey;
|
|
22646
23271
|
}
|
|
22647
23272
|
const key = process.env.LATTICE_ENCRYPTION_KEY || DEFAULT_ENCRYPTION_KEY;
|
|
22648
|
-
cachedKey = (0,
|
|
23273
|
+
cachedKey = (0, import_crypto3.pbkdf2Sync)(key, "lattice-encryption-salt", ITERATIONS, 32, "sha256");
|
|
22649
23274
|
if (!keyValidated) {
|
|
22650
23275
|
keyValidated = true;
|
|
22651
23276
|
validateEncryptionKey();
|
|
@@ -22654,10 +23279,10 @@ function getEncryptionKey() {
|
|
|
22654
23279
|
}
|
|
22655
23280
|
function encrypt(plaintext, key) {
|
|
22656
23281
|
const actualKey = key || getEncryptionKey();
|
|
22657
|
-
const salt = (0,
|
|
22658
|
-
const iv = (0,
|
|
22659
|
-
const derivedKey = (0,
|
|
22660
|
-
const cipher = (0,
|
|
23282
|
+
const salt = (0, import_crypto3.randomBytes)(SALT_LENGTH);
|
|
23283
|
+
const iv = (0, import_crypto3.randomBytes)(IV_LENGTH);
|
|
23284
|
+
const derivedKey = (0, import_crypto3.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
|
|
23285
|
+
const cipher = (0, import_crypto3.createCipheriv)(ALGORITHM, derivedKey, iv);
|
|
22661
23286
|
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
22662
23287
|
const authTag = cipher.getAuthTag();
|
|
22663
23288
|
return Buffer.concat([salt, iv, encrypted, authTag]).toString("base64");
|
|
@@ -22669,8 +23294,8 @@ function decrypt(encrypted, key) {
|
|
|
22669
23294
|
const iv = data.subarray(SALT_LENGTH, SALT_LENGTH + IV_LENGTH);
|
|
22670
23295
|
const authTag = data.subarray(-16);
|
|
22671
23296
|
const ciphertext = data.subarray(SALT_LENGTH + IV_LENGTH, -16);
|
|
22672
|
-
const derivedKey = (0,
|
|
22673
|
-
const decipher = (0,
|
|
23297
|
+
const derivedKey = (0, import_crypto3.pbkdf2Sync)(actualKey, salt, ITERATIONS, 32, "sha256");
|
|
23298
|
+
const decipher = (0, import_crypto3.createDecipheriv)(ALGORITHM, derivedKey, iv);
|
|
22674
23299
|
decipher.setAuthTag(authTag);
|
|
22675
23300
|
return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
22676
23301
|
}
|
|
@@ -22708,6 +23333,7 @@ function clearEncryptionKeyCache() {
|
|
|
22708
23333
|
CompositeBackend,
|
|
22709
23334
|
ConsoleLoggerClient,
|
|
22710
23335
|
CustomMetricsClient,
|
|
23336
|
+
CustomMiddlewareRegistry,
|
|
22711
23337
|
DaytonaInstance,
|
|
22712
23338
|
DaytonaProvider,
|
|
22713
23339
|
DefaultScheduleClient,
|
|
@@ -22718,6 +23344,7 @@ function clearEncryptionKeyCache() {
|
|
|
22718
23344
|
FileSystemSkillStore,
|
|
22719
23345
|
FilesystemBackend,
|
|
22720
23346
|
HumanMessage,
|
|
23347
|
+
InMemoryA2AApiKeyStore,
|
|
22721
23348
|
InMemoryAssistantStore,
|
|
22722
23349
|
InMemoryBindingStore,
|
|
22723
23350
|
InMemoryChannelInstallationStore,
|