@dxos/agent-runtime 0.14.0 → 0.16.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/lib/chunk-AgentService.mjs +7 -5
- package/dist/lib/chunk-AgentService.mjs.map +1 -1
- package/dist/lib/index.mjs +1 -2
- package/dist/lib/testing.mjs +1 -1
- package/dist/lib/testing.mjs.map +1 -1
- package/dist/types/src/agent-service/AgentService.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +20 -20
- package/src/agent-service/AgentService.test.ts +41 -0
- package/src/agent-service/AgentService.ts +9 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/agent-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "Local agent process runtime (agent-service) and assistant-coupled test helpers.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -38,30 +38,30 @@
|
|
|
38
38
|
"src"
|
|
39
39
|
],
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"effect": "4.0.
|
|
42
|
-
"@dxos/ai": "0.
|
|
43
|
-
"@dxos/compute": "0.
|
|
44
|
-
"@dxos/compute-runtime": "0.
|
|
45
|
-
"@dxos/echo": "0.
|
|
46
|
-
"@dxos/echo-client": "0.
|
|
47
|
-
"@dxos/effect": "0.
|
|
48
|
-
"@dxos/keys": "0.
|
|
49
|
-
"@dxos/link": "0.
|
|
50
|
-
"@dxos/log": "0.
|
|
51
|
-
"@dxos/mcp-client": "0.
|
|
52
|
-
"@dxos/schema": "0.
|
|
53
|
-
"@dxos/types": "0.
|
|
54
|
-
"@dxos/util": "0.
|
|
41
|
+
"effect": "4.0.4",
|
|
42
|
+
"@dxos/ai": "0.16.0",
|
|
43
|
+
"@dxos/compute": "0.16.0",
|
|
44
|
+
"@dxos/compute-runtime": "0.16.0",
|
|
45
|
+
"@dxos/echo": "0.16.0",
|
|
46
|
+
"@dxos/echo-client": "0.16.0",
|
|
47
|
+
"@dxos/effect": "0.16.0",
|
|
48
|
+
"@dxos/keys": "0.16.0",
|
|
49
|
+
"@dxos/link": "0.16.0",
|
|
50
|
+
"@dxos/log": "0.16.0",
|
|
51
|
+
"@dxos/mcp-client": "0.16.0",
|
|
52
|
+
"@dxos/schema": "0.16.0",
|
|
53
|
+
"@dxos/types": "0.16.0",
|
|
54
|
+
"@dxos/util": "0.16.0"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@effect/vitest": "4.0.
|
|
57
|
+
"@effect/vitest": "4.0.4",
|
|
58
58
|
"vitest": "4.1.10",
|
|
59
|
-
"@dxos/assistant": "0.
|
|
60
|
-
"@dxos/errors": "0.
|
|
59
|
+
"@dxos/assistant": "0.16.0",
|
|
60
|
+
"@dxos/errors": "0.16.0"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
|
-
"effect": "4.0.
|
|
64
|
-
"@dxos/assistant": "^0.
|
|
63
|
+
"effect": "4.0.4",
|
|
64
|
+
"@dxos/assistant": "^0.16.0"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|
|
@@ -891,6 +891,47 @@ describe('Agent Service (control plane)', () => {
|
|
|
891
891
|
TestHelpers.provideTestContext,
|
|
892
892
|
),
|
|
893
893
|
);
|
|
894
|
+
it.effect(
|
|
895
|
+
'session reuse tracks the harness selected on the chat',
|
|
896
|
+
Effect.fnUntraced(
|
|
897
|
+
function* (_) {
|
|
898
|
+
const processManager = yield* ProcessManager.ProcessManagerService;
|
|
899
|
+
|
|
900
|
+
const feed = yield* Database.add(Feed.make());
|
|
901
|
+
const chat = yield* Database.add(Chat.make({ feed: Ref.make(feed) }));
|
|
902
|
+
yield* Database.flush();
|
|
903
|
+
const target = Obj.getURI(chat);
|
|
904
|
+
|
|
905
|
+
const isActive = (state: Process.State) =>
|
|
906
|
+
state !== Process.State.SUCCEEDED && state !== Process.State.FAILED && state !== Process.State.TERMINATED;
|
|
907
|
+
const activePids = Effect.gen(function* () {
|
|
908
|
+
const processes = yield* processManager.list({ target, key: AGENT_PROCESS_KEY });
|
|
909
|
+
return processes.filter((process) => isActive(process.status.state)).map((process) => String(process.pid));
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
// Opening a chat spawns its process on the default harness before the user picks one.
|
|
913
|
+
const sessionA = yield* ComputeAgentService.getSession(chat);
|
|
914
|
+
const [pidA] = yield* activePids;
|
|
915
|
+
|
|
916
|
+
// The turn producer is chosen when the process starts, so picking a harness must respawn it.
|
|
917
|
+
Obj.update(chat, (chat) => {
|
|
918
|
+
chat.session = { harness: 'claude-code-edge' };
|
|
919
|
+
});
|
|
920
|
+
yield* Database.flush();
|
|
921
|
+
const sessionB = yield* ComputeAgentService.getSession(chat);
|
|
922
|
+
const [pidB] = yield* activePids;
|
|
923
|
+
expect(sessionB).not.toBe(sessionA);
|
|
924
|
+
expect(pidB).not.toBe(pidA);
|
|
925
|
+
expect(yield* activePids).toEqual([pidB]);
|
|
926
|
+
|
|
927
|
+
expect(yield* ComputeAgentService.getSession(chat)).toBe(sessionB);
|
|
928
|
+
|
|
929
|
+
yield* sessionB.terminate();
|
|
930
|
+
},
|
|
931
|
+
Effect.provide(TestLayer()),
|
|
932
|
+
TestHelpers.provideTestContext,
|
|
933
|
+
),
|
|
934
|
+
);
|
|
894
935
|
it.effect(
|
|
895
936
|
'traces a turn run through the agent process',
|
|
896
937
|
Effect.fnUntraced(
|
|
@@ -10,6 +10,7 @@ import * as Layer from 'effect/Layer';
|
|
|
10
10
|
import * as Atom from 'effect/reactivity/Atom';
|
|
11
11
|
import * as Semaphore from 'effect/Semaphore';
|
|
12
12
|
|
|
13
|
+
import { SessionConfig } from '@dxos/ai';
|
|
13
14
|
import { AiContext, type HarnessControlRpcs } from '@dxos/assistant';
|
|
14
15
|
import * as Chat from '@dxos/assistant/Chat';
|
|
15
16
|
import * as AgentService from '@dxos/compute/AgentService';
|
|
@@ -145,13 +146,14 @@ export const layer = (opts?: Options): Layer.Layer<AgentService.AgentService, ne
|
|
|
145
146
|
return { kind: 'edge', space: spaceId };
|
|
146
147
|
};
|
|
147
148
|
|
|
148
|
-
// The agent's model and steering instructions are bound to its process at spawn time, so
|
|
149
|
-
// cache tracks what each session was created with. A chat repointed at a different model
|
|
150
|
-
// instructions ref tears down the old process and spawns a fresh one (see below).
|
|
149
|
+
// The agent's model, harness and steering instructions are bound to its process at spawn time, so
|
|
150
|
+
// the cache tracks what each session was created with. A chat repointed at a different model,
|
|
151
|
+
// harness or instructions ref tears down the old process and spawns a fresh one (see below).
|
|
151
152
|
const sessionCache = new Map<
|
|
152
153
|
string,
|
|
153
154
|
{
|
|
154
155
|
model: string | undefined;
|
|
156
|
+
harness: string;
|
|
155
157
|
provider: DXN.DXN | undefined;
|
|
156
158
|
instructions: string | undefined;
|
|
157
159
|
location: AgentService.AgentLocation;
|
|
@@ -249,6 +251,7 @@ export const layer = (opts?: Options): Layer.Layer<AgentService.AgentService, ne
|
|
|
249
251
|
// Read off the chat rather than passed in: the process is bound to the chat, so its
|
|
250
252
|
// model and steering are whatever the chat points at when the process is spawned.
|
|
251
253
|
const model = chat.session?.model;
|
|
254
|
+
const harness = SessionConfig.harnessOf(chat.session);
|
|
252
255
|
const instructions = chat.instructions?.uri;
|
|
253
256
|
const location: AgentService.AgentLocation = options?.location ?? 'local';
|
|
254
257
|
const executable = executableFor(chat, provider);
|
|
@@ -262,6 +265,7 @@ export const layer = (opts?: Options): Layer.Layer<AgentService.AgentService, ne
|
|
|
262
265
|
if (cached) {
|
|
263
266
|
if (
|
|
264
267
|
cached.model === model &&
|
|
268
|
+
cached.harness === harness &&
|
|
265
269
|
cached.provider === provider &&
|
|
266
270
|
cached.instructions === instructions &&
|
|
267
271
|
cached.location === location &&
|
|
@@ -272,7 +276,7 @@ export const layer = (opts?: Options): Layer.Layer<AgentService.AgentService, ne
|
|
|
272
276
|
}
|
|
273
277
|
|
|
274
278
|
if (!Process.isTerminal(cached.handle.status.state)) {
|
|
275
|
-
// Model, provider, steering instructions, location or process changed (e.g. the user
|
|
279
|
+
// Model, harness, provider, steering instructions, location or process changed (e.g. the user
|
|
276
280
|
// toggled online/offline, or moved the chat to the cloud): terminate the
|
|
277
281
|
// existing process so the conversation continues on a fresh process bound to the new
|
|
278
282
|
// configuration. Conversation history is preserved via the feed, which the new
|
|
@@ -363,6 +367,7 @@ export const layer = (opts?: Options): Layer.Layer<AgentService.AgentService, ne
|
|
|
363
367
|
const session = makeSession(handle, chat, feed, releaseSession, isFinished, resubmit);
|
|
364
368
|
sessionCache.set(chat.id, {
|
|
365
369
|
model,
|
|
370
|
+
harness,
|
|
366
371
|
provider,
|
|
367
372
|
instructions,
|
|
368
373
|
location,
|