macro-agent 0.1.10 → 0.1.11
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/CLAUDE.md +97 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +42 -6
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/adapters/tasks-adapter.d.ts.map +1 -1
- package/dist/adapters/tasks-adapter.js +3 -0
- package/dist/adapters/tasks-adapter.js.map +1 -1
- package/dist/adapters/types.d.ts +1 -0
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.d.ts.map +1 -1
- package/dist/agent/agent-manager-v2.js +74 -11
- package/dist/agent/agent-manager-v2.js.map +1 -1
- package/dist/agent/agent-store.d.ts +10 -0
- package/dist/agent/agent-store.d.ts.map +1 -1
- package/dist/agent/agent-store.js +22 -0
- package/dist/agent/agent-store.js.map +1 -1
- package/dist/boot-v2.d.ts +88 -1
- package/dist/boot-v2.d.ts.map +1 -1
- package/dist/boot-v2.js +343 -7
- package/dist/boot-v2.js.map +1 -1
- package/dist/cli/acp.js +4 -0
- package/dist/cli/acp.js.map +1 -1
- package/dist/lifecycle/cascade.d.ts +25 -2
- package/dist/lifecycle/cascade.d.ts.map +1 -1
- package/dist/lifecycle/cascade.js +70 -2
- package/dist/lifecycle/cascade.js.map +1 -1
- package/dist/map/cascade-action-handler.d.ts +24 -0
- package/dist/map/cascade-action-handler.d.ts.map +1 -0
- package/dist/map/cascade-action-handler.js +170 -0
- package/dist/map/cascade-action-handler.js.map +1 -0
- package/dist/map/cascade-bridge.d.ts.map +1 -1
- package/dist/map/cascade-bridge.js +42 -5
- package/dist/map/cascade-bridge.js.map +1 -1
- package/dist/map/coordination-handler.d.ts.map +1 -1
- package/dist/map/coordination-handler.js +12 -1
- package/dist/map/coordination-handler.js.map +1 -1
- package/dist/map/server.d.ts.map +1 -1
- package/dist/map/server.js +172 -1
- package/dist/map/server.js.map +1 -1
- package/dist/map/sidecar.d.ts.map +1 -1
- package/dist/map/sidecar.js +18 -2
- package/dist/map/sidecar.js.map +1 -1
- package/dist/map/types.d.ts +2 -0
- package/dist/map/types.d.ts.map +1 -1
- package/dist/workspace/git-cascade-adapter.d.ts +1 -1
- package/dist/workspace/git-cascade-adapter.d.ts.map +1 -1
- package/dist/workspace/git-cascade-adapter.js +26 -0
- package/dist/workspace/git-cascade-adapter.js.map +1 -1
- package/dist/workspace/landing/merge-to-parent.d.ts.map +1 -1
- package/dist/workspace/landing/merge-to-parent.js +1 -0
- package/dist/workspace/landing/merge-to-parent.js.map +1 -1
- package/dist/workspace/recovery/spawn-resolver.d.ts.map +1 -1
- package/dist/workspace/recovery/spawn-resolver.js +8 -1
- package/dist/workspace/recovery/spawn-resolver.js.map +1 -1
- package/dist/workspace/types-v3.d.ts +7 -0
- package/dist/workspace/types-v3.d.ts.map +1 -1
- package/dist/workspace/types-v3.js.map +1 -1
- package/dist/workspace/types.d.ts +17 -0
- package/dist/workspace/types.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.d.ts +9 -0
- package/dist/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/workspace/workspace-manager.js +45 -2
- package/dist/workspace/workspace-manager.js.map +1 -1
- package/docs/design/task-dispatcher.md +880 -0
- package/package.json +3 -2
- package/src/__tests__/boot-v2.test.ts +435 -0
- package/src/__tests__/e2e/acp-over-map.e2e.test.ts +92 -0
- package/src/__tests__/e2e/bootstrap.e2e.test.ts +319 -0
- package/src/__tests__/e2e/dispatch-coordination.e2e.test.ts +495 -0
- package/src/__tests__/e2e/dispatch-live.e2e.test.ts +564 -0
- package/src/__tests__/e2e/dispatch-opentasks.e2e.test.ts +496 -0
- package/src/__tests__/e2e/dispatch-phase2-live.e2e.test.ts +456 -0
- package/src/__tests__/e2e/dispatch-phase2.e2e.test.ts +386 -0
- package/src/__tests__/e2e/dispatch.e2e.test.ts +376 -0
- package/src/acp/macro-agent.ts +41 -6
- package/src/adapters/__tests__/tasks-adapter.test.ts +1 -0
- package/src/adapters/tasks-adapter.ts +3 -0
- package/src/adapters/types.ts +1 -0
- package/src/agent/__tests__/agent-store.test.ts +52 -0
- package/src/agent/agent-manager-v2.ts +79 -11
- package/src/agent/agent-store.ts +24 -0
- package/src/boot-v2.ts +522 -35
- package/src/cli/acp.ts +4 -0
- package/src/lifecycle/__tests__/cascade-consolidation.test.ts +240 -0
- package/src/lifecycle/cascade.ts +77 -2
- package/src/map/__tests__/emit-event.test.ts +71 -0
- package/src/map/cascade-action-handler.ts +205 -0
- package/src/map/cascade-bridge.ts +43 -5
- package/src/map/coordination-handler.ts +13 -1
- package/src/map/server.ts +178 -1
- package/src/map/sidecar.ts +19 -2
- package/src/map/types.ts +3 -0
- package/src/workspace/__tests__/land-dispatch.test.ts +214 -0
- package/src/workspace/git-cascade-adapter.ts +30 -3
- package/src/workspace/landing/__tests__/strategies.test.ts +42 -0
- package/src/workspace/landing/merge-to-parent.ts +1 -0
- package/src/workspace/recovery/spawn-resolver.ts +8 -1
- package/src/workspace/types-v3.ts +7 -0
- package/src/workspace/types.ts +20 -0
- package/src/workspace/workspace-manager.ts +61 -2
- package/dist/workspace/dataplane-adapter.d.ts +0 -260
- package/dist/workspace/dataplane-adapter.d.ts.map +0 -1
- package/dist/workspace/dataplane-adapter.js +0 -416
- package/dist/workspace/dataplane-adapter.js.map +0 -1
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bootstrap & Spawn-Options E2E Tests
|
|
3
|
+
*
|
|
4
|
+
* Boots macro-agent with the MAP server enabled and verifies:
|
|
5
|
+
* 1. `bootstrap.coordinator: true` (programmatic) auto-spawns a coordinator
|
|
6
|
+
* that's discoverable via the MAP protocol.
|
|
7
|
+
* 2. `MACRO_BOOTSTRAP_COORDINATOR=true` env var triggers the same path —
|
|
8
|
+
* this is how `openswarm` / openhive get bootstrap without modifying
|
|
9
|
+
* openswarm's whitelisted bootConfig pass-through.
|
|
10
|
+
* 3. `_macro/spawnAgent` extension forwards the full SpawnAgentOptions
|
|
11
|
+
* surface (permissionMode, agentType, customPrompt, config, taskRef)
|
|
12
|
+
* so the agent record carries the requested settings.
|
|
13
|
+
*
|
|
14
|
+
* Run:
|
|
15
|
+
* npx vitest run --config vitest.e2e.config.ts \
|
|
16
|
+
* src/__tests__/e2e/bootstrap.e2e.test.ts
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
20
|
+
import * as fs from "fs";
|
|
21
|
+
import * as path from "path";
|
|
22
|
+
import * as os from "os";
|
|
23
|
+
import { bootV2, type MacroAgentSystemV2 } from "../../boot-v2.js";
|
|
24
|
+
import { ClientConnection } from "@multi-agent-protocol/sdk";
|
|
25
|
+
|
|
26
|
+
/** Wait for a coordinator agent to land in the agent store. */
|
|
27
|
+
async function waitForCoordinator(
|
|
28
|
+
system: MacroAgentSystemV2,
|
|
29
|
+
timeoutMs = 5000,
|
|
30
|
+
): Promise<{ id: string; cwd?: string | null; role: string } | null> {
|
|
31
|
+
const deadline = Date.now() + timeoutMs;
|
|
32
|
+
while (Date.now() < deadline) {
|
|
33
|
+
const agents = system.agentStore.listAgents({ role: "coordinator" });
|
|
34
|
+
if (agents.length > 0) return agents[0];
|
|
35
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function freshDir(prefix: string): string {
|
|
41
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
// Bootstrap: programmatic
|
|
46
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
describe("Bootstrap E2E — programmatic config", () => {
|
|
49
|
+
let system: MacroAgentSystemV2 | null = null;
|
|
50
|
+
let client: ClientConnection | null = null;
|
|
51
|
+
let dir: string;
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
dir = freshDir("bootstrap-prog-");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
afterEach(async () => {
|
|
58
|
+
if (client) {
|
|
59
|
+
try { await client.disconnect(); } catch { /* */ }
|
|
60
|
+
client = null;
|
|
61
|
+
}
|
|
62
|
+
if (system) {
|
|
63
|
+
await system.shutdown();
|
|
64
|
+
system = null;
|
|
65
|
+
}
|
|
66
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* */ }
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("auto-spawns a coordinator when bootstrap.coordinator: true", async () => {
|
|
70
|
+
system = await bootV2({
|
|
71
|
+
baseDir: dir,
|
|
72
|
+
cwd: dir,
|
|
73
|
+
defaultPermissionMode: "auto-approve",
|
|
74
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
75
|
+
bootstrap: { coordinator: true },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const agent = await waitForCoordinator(system);
|
|
79
|
+
expect(agent).not.toBeNull();
|
|
80
|
+
expect(agent!.role).toBe("coordinator");
|
|
81
|
+
expect(agent!.cwd).toBe(dir);
|
|
82
|
+
|
|
83
|
+
// Discoverable via MAP listAgents. The lifecycle handler that registers
|
|
84
|
+
// the agent in mapServer.agents fires after the AgentManager.spawn()
|
|
85
|
+
// promise resolves, but listAgents may race that registration in the
|
|
86
|
+
// first poll cycle. Poll briefly until it appears.
|
|
87
|
+
const url = system.mapServerInstance!.getUrl();
|
|
88
|
+
client = await ClientConnection.connect(url, { name: "bootstrap-test-client" });
|
|
89
|
+
|
|
90
|
+
let coordinators: unknown[] = [];
|
|
91
|
+
const deadline = Date.now() + 5000;
|
|
92
|
+
while (Date.now() < deadline) {
|
|
93
|
+
const result = await client.listAgents();
|
|
94
|
+
coordinators = result.agents.filter((a: any) => a.role === "coordinator");
|
|
95
|
+
if (coordinators.length >= 1) break;
|
|
96
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
97
|
+
}
|
|
98
|
+
expect(coordinators.length).toBeGreaterThanOrEqual(1);
|
|
99
|
+
}, 20000);
|
|
100
|
+
|
|
101
|
+
it("uses bootstrap.coordinator.cwd when provided", async () => {
|
|
102
|
+
const projectDir = path.join(dir, "project-x");
|
|
103
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
104
|
+
|
|
105
|
+
system = await bootV2({
|
|
106
|
+
baseDir: dir,
|
|
107
|
+
cwd: dir,
|
|
108
|
+
defaultPermissionMode: "auto-approve",
|
|
109
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
110
|
+
bootstrap: { coordinator: { cwd: projectDir } },
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const agent = await waitForCoordinator(system);
|
|
114
|
+
expect(agent!.cwd).toBe(projectDir);
|
|
115
|
+
}, 20000);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
119
|
+
// Bootstrap: env-var bridge
|
|
120
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
describe("Bootstrap E2E — env-var bridge", () => {
|
|
123
|
+
let system: MacroAgentSystemV2 | null = null;
|
|
124
|
+
let dir: string;
|
|
125
|
+
|
|
126
|
+
beforeEach(() => {
|
|
127
|
+
dir = freshDir("bootstrap-env-");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
afterEach(async () => {
|
|
131
|
+
if (system) {
|
|
132
|
+
await system.shutdown();
|
|
133
|
+
system = null;
|
|
134
|
+
}
|
|
135
|
+
delete process.env.MACRO_BOOTSTRAP_COORDINATOR;
|
|
136
|
+
delete process.env.MACRO_BOOTSTRAP_CWD;
|
|
137
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* */ }
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("MACRO_BOOTSTRAP_COORDINATOR=true triggers bootstrap", async () => {
|
|
141
|
+
process.env.MACRO_BOOTSTRAP_COORDINATOR = "true";
|
|
142
|
+
|
|
143
|
+
system = await bootV2({
|
|
144
|
+
baseDir: dir,
|
|
145
|
+
cwd: dir,
|
|
146
|
+
defaultPermissionMode: "auto-approve",
|
|
147
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const agent = await waitForCoordinator(system);
|
|
151
|
+
expect(agent).not.toBeNull();
|
|
152
|
+
expect(agent!.cwd).toBe(dir);
|
|
153
|
+
}, 20000);
|
|
154
|
+
|
|
155
|
+
it("MACRO_BOOTSTRAP_CWD overrides default cwd", async () => {
|
|
156
|
+
const projectDir = path.join(dir, "env-project");
|
|
157
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
158
|
+
|
|
159
|
+
process.env.MACRO_BOOTSTRAP_COORDINATOR = "true";
|
|
160
|
+
process.env.MACRO_BOOTSTRAP_CWD = projectDir;
|
|
161
|
+
|
|
162
|
+
system = await bootV2({
|
|
163
|
+
baseDir: dir,
|
|
164
|
+
cwd: dir,
|
|
165
|
+
defaultPermissionMode: "auto-approve",
|
|
166
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const agent = await waitForCoordinator(system);
|
|
170
|
+
expect(agent!.cwd).toBe(projectDir);
|
|
171
|
+
}, 20000);
|
|
172
|
+
|
|
173
|
+
it("does NOT spawn when env var is unset", async () => {
|
|
174
|
+
system = await bootV2({
|
|
175
|
+
baseDir: dir,
|
|
176
|
+
cwd: dir,
|
|
177
|
+
defaultPermissionMode: "auto-approve",
|
|
178
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Give any rogue spawn a chance to fire before asserting absence.
|
|
182
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
183
|
+
const agents = system.agentStore.listAgents({ role: "coordinator" });
|
|
184
|
+
expect(agents).toHaveLength(0);
|
|
185
|
+
}, 20000);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
189
|
+
// Spawn options forwarding via _macro/spawnAgent
|
|
190
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
describe("Spawn-options forwarding E2E — _macro/spawnAgent", () => {
|
|
193
|
+
let system: MacroAgentSystemV2 | null = null;
|
|
194
|
+
let client: ClientConnection | null = null;
|
|
195
|
+
let dir: string;
|
|
196
|
+
|
|
197
|
+
beforeEach(async () => {
|
|
198
|
+
dir = freshDir("spawn-opts-");
|
|
199
|
+
system = await bootV2({
|
|
200
|
+
baseDir: dir,
|
|
201
|
+
cwd: dir,
|
|
202
|
+
defaultPermissionMode: "auto-approve",
|
|
203
|
+
mapServer: { enabled: true, port: 0, host: "127.0.0.1" },
|
|
204
|
+
});
|
|
205
|
+
const url = system.mapServerInstance!.getUrl();
|
|
206
|
+
client = await ClientConnection.connect(url, { name: "spawn-opts-client" });
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
afterEach(async () => {
|
|
210
|
+
if (client) {
|
|
211
|
+
try { await client.disconnect(); } catch { /* */ }
|
|
212
|
+
client = null;
|
|
213
|
+
}
|
|
214
|
+
if (system) {
|
|
215
|
+
await system.shutdown();
|
|
216
|
+
system = null;
|
|
217
|
+
}
|
|
218
|
+
try { fs.rmSync(dir, { recursive: true, force: true }); } catch { /* */ }
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("forwards role, cwd, task to the spawned agent record", async () => {
|
|
222
|
+
const projectDir = path.join(dir, "proj-a");
|
|
223
|
+
fs.mkdirSync(projectDir, { recursive: true });
|
|
224
|
+
|
|
225
|
+
const result = await client!.callExtension("_macro/spawnAgent", {
|
|
226
|
+
role: "coordinator",
|
|
227
|
+
cwd: projectDir,
|
|
228
|
+
task: "Test task description",
|
|
229
|
+
}) as { agent?: { id?: string; localId?: string } };
|
|
230
|
+
|
|
231
|
+
const localId = result.agent?.localId;
|
|
232
|
+
expect(localId).toBeTruthy();
|
|
233
|
+
|
|
234
|
+
const record = system!.agentStore.getAgent(localId!);
|
|
235
|
+
expect(record).not.toBeNull();
|
|
236
|
+
expect(record!.role).toBe("coordinator");
|
|
237
|
+
expect(record!.cwd).toBe(projectDir);
|
|
238
|
+
expect(record!.task).toBe("Test task description");
|
|
239
|
+
expect(record!.parent_id).toBeNull();
|
|
240
|
+
}, 15000);
|
|
241
|
+
|
|
242
|
+
it("forwards config (model, maxTokens, temperature) onto the agent record", async () => {
|
|
243
|
+
const result = await client!.callExtension("_macro/spawnAgent", {
|
|
244
|
+
role: "coordinator",
|
|
245
|
+
cwd: dir,
|
|
246
|
+
task: "Config test",
|
|
247
|
+
config: {
|
|
248
|
+
model: "claude-sonnet-4-6",
|
|
249
|
+
maxTokens: 4096,
|
|
250
|
+
temperature: 0.42,
|
|
251
|
+
},
|
|
252
|
+
}) as { agent?: { localId?: string } };
|
|
253
|
+
|
|
254
|
+
const localId = result.agent?.localId;
|
|
255
|
+
expect(localId).toBeTruthy();
|
|
256
|
+
|
|
257
|
+
const record = system!.agentStore.getAgent(localId!);
|
|
258
|
+
expect(record!.config).toBeDefined();
|
|
259
|
+
expect(record!.config!.model).toBe("claude-sonnet-4-6");
|
|
260
|
+
expect(record!.config!.maxTokens).toBe(4096);
|
|
261
|
+
expect(record!.config!.temperature).toBeCloseTo(0.42);
|
|
262
|
+
}, 15000);
|
|
263
|
+
|
|
264
|
+
it("forwards customPrompt by reflecting it in the agent's task surface", async () => {
|
|
265
|
+
// customPrompt is woven into the system prompt at spawn time; we can't
|
|
266
|
+
// easily inspect the assembled prompt from outside, but we can verify the
|
|
267
|
+
// spawn succeeds when customPrompt is set (no validation rejection /
|
|
268
|
+
// dropped-field bug). Combined with the unit check that the wire forwards
|
|
269
|
+
// the field, this confirms the round trip is intact.
|
|
270
|
+
const result = await client!.callExtension("_macro/spawnAgent", {
|
|
271
|
+
role: "coordinator",
|
|
272
|
+
cwd: dir,
|
|
273
|
+
task: "Custom prompt test",
|
|
274
|
+
customPrompt: "You are a meticulous code reviewer. Cite line numbers.",
|
|
275
|
+
}) as { agent?: { localId?: string; id?: string } };
|
|
276
|
+
|
|
277
|
+
expect(result.agent?.localId).toBeTruthy();
|
|
278
|
+
const record = system!.agentStore.getAgent(result.agent!.localId!);
|
|
279
|
+
expect(record).not.toBeNull();
|
|
280
|
+
expect(record!.role).toBe("coordinator");
|
|
281
|
+
}, 15000);
|
|
282
|
+
|
|
283
|
+
it("ignores unknown role when role is omitted (defaults to worker)", async () => {
|
|
284
|
+
const result = await client!.callExtension("_macro/spawnAgent", {
|
|
285
|
+
cwd: dir,
|
|
286
|
+
task: "No role specified",
|
|
287
|
+
}) as { agent?: { localId?: string } };
|
|
288
|
+
|
|
289
|
+
const localId = result.agent?.localId;
|
|
290
|
+
const record = system!.agentStore.getAgent(localId!);
|
|
291
|
+
// The handler defaults role to "worker" when omitted.
|
|
292
|
+
expect(record!.role).toBe("worker");
|
|
293
|
+
}, 15000);
|
|
294
|
+
|
|
295
|
+
it("multiple spawns with same cwd produce distinct agents (no implicit dedup)", async () => {
|
|
296
|
+
// The spawn endpoint always spawns. Get-or-create semantics live on the
|
|
297
|
+
// openhive caller side, not in macro-agent's _macro/spawnAgent.
|
|
298
|
+
const r1 = await client!.callExtension("_macro/spawnAgent", {
|
|
299
|
+
role: "coordinator",
|
|
300
|
+
cwd: dir,
|
|
301
|
+
task: "First",
|
|
302
|
+
}) as { agent?: { localId?: string } };
|
|
303
|
+
|
|
304
|
+
const r2 = await client!.callExtension("_macro/spawnAgent", {
|
|
305
|
+
role: "coordinator",
|
|
306
|
+
cwd: dir,
|
|
307
|
+
task: "Second",
|
|
308
|
+
}) as { agent?: { localId?: string } };
|
|
309
|
+
|
|
310
|
+
expect(r1.agent?.localId).toBeTruthy();
|
|
311
|
+
expect(r2.agent?.localId).toBeTruthy();
|
|
312
|
+
expect(r1.agent?.localId).not.toBe(r2.agent?.localId);
|
|
313
|
+
|
|
314
|
+
const r1Record = system!.agentStore.getAgent(r1.agent!.localId!);
|
|
315
|
+
const r2Record = system!.agentStore.getAgent(r2.agent!.localId!);
|
|
316
|
+
expect(r1Record!.task).toBe("First");
|
|
317
|
+
expect(r2Record!.task).toBe("Second");
|
|
318
|
+
}, 20000);
|
|
319
|
+
});
|