@dxos/agent-runtime 0.0.0 → 0.11.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 +789 -0
- package/dist/lib/chunk-AgentService.mjs.map +1 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/testing.mjs +294 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/types/src/agent-service/AgentService.d.ts +4 -4
- package/dist/types/src/agent-service/AgentService.d.ts.map +1 -1
- package/dist/types/src/agent-service/agent-process.d.ts +173 -5
- package/dist/types/src/agent-service/agent-process.d.ts.map +1 -1
- package/dist/types/src/agent-service/delegation-scripted.test.d.ts +2 -0
- package/dist/types/src/agent-service/delegation-scripted.test.d.ts.map +1 -0
- package/dist/types/src/assistant-session-tests/scripted-loop.test.d.ts +2 -0
- package/dist/types/src/assistant-session-tests/scripted-loop.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/testing/assistant-test-layer.d.ts +6 -2
- package/dist/types/src/testing/assistant-test-layer.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent.d.ts +70 -0
- package/dist/types/src/testing/test-agent.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -16
- package/src/agent-service/AgentService.conversations.json +1 -1
- package/src/agent-service/AgentService.test.ts +115 -58
- package/src/agent-service/AgentService.ts +44 -15
- package/src/agent-service/README.md +4 -4
- package/src/agent-service/agent-process.ts +31 -12
- package/src/agent-service/delegation-scripted.test.ts +123 -0
- package/src/assistant-session-tests/request.conversations.json +1 -1
- package/src/assistant-session-tests/request.test.ts +2 -2
- package/src/assistant-session-tests/scripted-loop.test.ts +119 -0
- package/src/assistant-session-tests/xml-response.conversations.json +1 -1
- package/src/assistant-session-tests/xml-response.test.ts +2 -2
- package/src/functions.conversations.json +1 -1
- package/src/functions.test.ts +2 -2
- package/src/index.ts +0 -2
- package/src/testing/assistant-test-layer.ts +32 -1
- package/src/testing/index.ts +3 -0
- package/src/testing/test-agent.ts +104 -0
- package/dist/lib/neutral/chunk-EZKG2ZGG.mjs +0 -754
- package/dist/lib/neutral/chunk-EZKG2ZGG.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -9
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/testing/index.mjs +0 -285
- package/dist/lib/neutral/testing/index.mjs.map +0 -7
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import type * as Scope from 'effect/Scope';
|
|
7
|
+
import * as Stream from 'effect/Stream';
|
|
8
|
+
|
|
9
|
+
import { CompleteBlock, PartialBlock } from '@dxos/assistant';
|
|
10
|
+
import { type AgentService, Trace } from '@dxos/compute';
|
|
11
|
+
import { Database, Feed, Filter, Obj } from '@dxos/echo';
|
|
12
|
+
import { BaseError, type BaseErrorOptions } from '@dxos/errors';
|
|
13
|
+
import { Message } from '@dxos/types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Buffered view of a session's ephemeral block events — the headless equivalent of what the chat
|
|
17
|
+
* UI renders while a request streams.
|
|
18
|
+
*/
|
|
19
|
+
export interface EphemeralCollector {
|
|
20
|
+
/** Snapshot of `PartialBlock` payloads observed so far, in arrival order. */
|
|
21
|
+
partialBlocks: () => readonly Trace.PayloadType<typeof PartialBlock>[];
|
|
22
|
+
/** Snapshot of `CompleteBlock` payloads observed so far, in arrival order. */
|
|
23
|
+
completeBlocks: () => readonly Trace.PayloadType<typeof CompleteBlock>[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Forks a collector over {@link AgentService.Session.subscribeEphemeral} so a test can assert the
|
|
28
|
+
* streaming path (partial → complete blocks) without a UI. The fork is scoped: use with
|
|
29
|
+
* `it.scoped` (or an explicit scope) so the subscription is interrupted on test close.
|
|
30
|
+
*/
|
|
31
|
+
export const collectEphemeral = (
|
|
32
|
+
session: AgentService.Session,
|
|
33
|
+
): Effect.Effect<EphemeralCollector, never, Scope.Scope> =>
|
|
34
|
+
Effect.gen(function* () {
|
|
35
|
+
const partial: Trace.PayloadType<typeof PartialBlock>[] = [];
|
|
36
|
+
const complete: Trace.PayloadType<typeof CompleteBlock>[] = [];
|
|
37
|
+
yield* session.subscribeEphemeral().pipe(
|
|
38
|
+
Stream.runForEach((message) =>
|
|
39
|
+
Effect.sync(() => {
|
|
40
|
+
for (const event of message.events) {
|
|
41
|
+
if (Trace.isOfType(PartialBlock, event)) {
|
|
42
|
+
partial.push(event.data);
|
|
43
|
+
} else if (Trace.isOfType(CompleteBlock, event)) {
|
|
44
|
+
complete.push(event.data);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}),
|
|
48
|
+
),
|
|
49
|
+
Effect.forkScoped,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
partialBlocks: () => [...partial],
|
|
54
|
+
completeBlocks: () => [...complete],
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export class WaitForMessageTimeoutError extends BaseError.extend('WaitForMessageTimeoutError') {
|
|
59
|
+
constructor(timeout: number, options?: Omit<BaseErrorOptions, 'context'>) {
|
|
60
|
+
super({
|
|
61
|
+
message: `Timed out after ${timeout}ms waiting for a matching feed message.`,
|
|
62
|
+
context: { timeout },
|
|
63
|
+
...options,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface WaitForMessageOptions {
|
|
69
|
+
/** Overall deadline in milliseconds. @default 10_000 */
|
|
70
|
+
timeout?: number;
|
|
71
|
+
/** Poll interval in milliseconds. @default 100 */
|
|
72
|
+
interval?: number;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Polls the conversation feed until a message matches. Covers the gap left by
|
|
77
|
+
* `Session.waitForCompletion`, which settles when the *turn* completes — background sub-agents
|
|
78
|
+
* report back later, out of band. Polls on the real clock (not the Effect `TestClock`), so it works
|
|
79
|
+
* under `it.effect` and `it.scoped` alike.
|
|
80
|
+
*/
|
|
81
|
+
export const waitForMessage = (
|
|
82
|
+
feed: Feed.Feed,
|
|
83
|
+
predicate: (message: Message.Message) => boolean,
|
|
84
|
+
{ timeout = 10_000, interval = 100 }: WaitForMessageOptions = {},
|
|
85
|
+
): Effect.Effect<Message.Message, WaitForMessageTimeoutError, Database.Service> =>
|
|
86
|
+
Effect.gen(function* () {
|
|
87
|
+
const deadline = Date.now() + timeout;
|
|
88
|
+
do {
|
|
89
|
+
const items = yield* Feed.query(feed, Filter.type(Message.Message)).run;
|
|
90
|
+
const match = items.filter(Obj.instanceOf(Message.Message)).find(predicate);
|
|
91
|
+
if (match) {
|
|
92
|
+
return match;
|
|
93
|
+
}
|
|
94
|
+
yield* Effect.promise(() => new Promise((resolve) => setTimeout(resolve, interval)));
|
|
95
|
+
} while (Date.now() < deadline);
|
|
96
|
+
|
|
97
|
+
return yield* Effect.fail(new WaitForMessageTimeoutError(timeout));
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/** Convenience predicate: any block's text content contains the substring. */
|
|
101
|
+
export const messageTextIncludes =
|
|
102
|
+
(needle: string) =>
|
|
103
|
+
(message: Message.Message): boolean =>
|
|
104
|
+
Message.extractText(message).includes(needle);
|