@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.
@@ -1 +1 @@
1
- {"version":3,"file":"testing.mjs","names":[],"sources":["../../src/testing/trace-pretty-print.ts","../../src/testing/assistant-test-layer.ts","../../src/testing/test-agent.ts","../../src/testing/ResearchService.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { ConsolePrinter } from '@dxos/ai';\nimport { FeedTraceSink } from '@dxos/compute-runtime';\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Filter, Query } from '@dxos/echo';\n\n/**\n * Pretty-prints assistant trace messages to stdout (Trace.CompleteBlock, process spawn/exit).\n */\nexport const prettyPrintTraceMessage = (message: Trace.Message): void => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.CompleteBlock, event)) {\n const tag = message.meta.processName ?? `${message.meta.pid ?? 'unknown'}`;\n console.log(`[${tag}] ${event.data.role.toUpperCase()}`);\n new ConsolePrinter({ tag }).printContentBlock(event.data.block);\n } else if (Trace.isOfType(Process.SpawnedEvent, event)) {\n console.log(`[${message.meta.pid}] Process spawned: ${message.meta.processName}`);\n } else if (Trace.isOfType(Process.ExitedEvent, event)) {\n console.log(`[${message.meta.pid}] Process exited: ${event.data.outcome}`);\n }\n }\n};\n\n/** {@link Trace.TraceSink} layer that mirrors {@link AssistantTestLayer}'s `tracing: 'pretty'` mode. */\nexport const traceSinkPrettyLayer = (): Layer.Layer<Trace.TraceSink> =>\n Layer.succeed(Trace.TraceSink, {\n write: prettyPrintTraceMessage,\n });\n\n/**\n * Subscribes to the space trace feed and pretty-prints newly appended messages.\n * Returns an unsubscribe function. Requires ambient {@link Database.Service}.\n */\nexport const traceFeedPrettyPrintSubscription = Effect.gen(function* () {\n const feed = yield* FeedTraceSink.getOrCreateTraceFeed();\n const queryResult = yield* Database.query(Query.select(Filter.type(Trace.Message)).from(feed));\n const seen = new Set((yield* Effect.promise(() => queryResult.run())).map((message) => message.id));\n\n return queryResult.subscribe((result) => {\n for (const message of result.results) {\n if (seen.has(message.id)) {\n continue;\n }\n seen.add(message.id);\n prettyPrintTraceMessage(message);\n }\n });\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Array from 'effect/Array';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Match from 'effect/Match';\nimport * as KeyValueStore from 'effect/persistence/KeyValueStore';\nimport * as AtomRegistry from 'effect/reactivity/AtomRegistry';\n\nimport { AiService, OpaqueToolkit, Provider } from '@dxos/ai';\nimport { type AiServicePreset, TestAiService } from '@dxos/ai/testing';\nimport { Alarm, Harness } from '@dxos/assistant';\nimport * as Chat from '@dxos/assistant/Chat';\nimport {\n FeedTraceSink,\n ProcessManager,\n ProcessOperationInvoker,\n RemoteProcessManager,\n RemoteTraceMonitor,\n TriggerDispatcher,\n TriggerStateStore,\n UnifiedProcessManager,\n configuredCredentialsLayer,\n} from '@dxos/compute-runtime';\nimport { TestDatabaseLayer } from '@dxos/compute-runtime/testing';\nimport * as AgentService from '@dxos/compute/AgentService';\nimport * as Credential from '@dxos/compute/Credential';\nimport * as Instructions from '@dxos/compute/Instructions';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\nimport * as Process from '@dxos/compute/Process';\nimport * as ServiceResolver from '@dxos/compute/ServiceResolver';\nimport * as Skill from '@dxos/compute/Skill';\nimport * as Trace from '@dxos/compute/Trace';\nimport * as Trigger from '@dxos/compute/Trigger';\nimport { Database, Feed, Hypergraph, Registry, Tag, Type } from '@dxos/echo';\nimport { registryLayer } from '@dxos/echo-client';\nimport { type TestContextService } from '@dxos/effect/testing';\nimport { DXN } from '@dxos/keys';\n\nimport { AgentService as AgentServiceRuntime } from '../agent-service/index.ts';\nimport { traceSinkPrettyLayer } from './trace-pretty-print.ts';\n\ninterface TestLayerOptions {\n aiServicePreset?: AiServicePreset;\n\n /**\n * Overrides the AI service entirely (e.g. a scripted model for deterministic e2e tests).\n * When set, `aiServicePreset` and `disableLlmMemoization` are ignored.\n */\n aiService?: Layer.Layer<AiService.AiService>;\n model?: DXN.DXN;\n /** Provider the model resolves through; defaults to `ollama` for the ollama preset, else `edge`. */\n provider?: DXN.DXN;\n operationHandlers?: OperationHandlerSet.OperationHandlerSet | OperationHandlerSet.OperationHandlerSet[];\n toolkits?: OpaqueToolkit.OpaqueToolkit[];\n types?: Type.AnyEntity[];\n skills?: Skill.Skill[];\n credentials?: Credential.ServiceCredential[];\n\n /**\n * Tracing configuration.\n * - `'feed'` persists trace events to a FeedTraceSink (queryable from the database).\n * @default 'noop'\n */\n tracing?: 'noop' | 'console' | 'pretty' | 'feed';\n\n disableLlmMemoization?: boolean;\n\n /**\n * Patterns matching run-specific values (e.g. timestamps derived from TestClock) that should be\n * canonicalized for memoized-conversation matching. Forwarded to `TestAiService`. Opt-in.\n */\n dynamicValuePatterns?: readonly RegExp[];\n\n /**\n * Options for the agent process (system prompt, tool backgrounding, delegation strategy, etc.).\n * The model defaults to the resolved test-layer model when not set here.\n */\n agent?: AgentServiceRuntime.Options;\n\n /**\n * Extra services to make available in the service resolver.\n * Operations can depend on those services. They may themselves require the {@link AgentService.AgentService}\n * (e.g. a service that wakes other conversations), which is served to them once it is built.\n */\n extraServices?: Layer.Layer<never, never, AgentService.AgentService>;\n}\n\nexport type AssistantTestServices =\n | LanguageModel.LanguageModel\n | Credential.CredentialsService\n | AgentService.AgentService\n | AiService.AiService\n | Database.Service\n | Registry.Service\n | OpaqueToolkit.OpaqueToolkitProvider\n | Operation.Service\n | ProcessManager.Service\n | RemoteProcessManager.Service\n | ProcessOperationInvoker.Service\n | Process.ManagerService\n | AtomRegistry.AtomRegistry\n | OperationHandlerSet.OperationHandlerProvider\n | KeyValueStore.KeyValueStore\n | ServiceResolver.ServiceResolver\n | Trace.TraceService\n | Trace.TraceSink\n | FeedTraceSink.FeedTraceSink;\n\nexport const AssistantTestLayer = (\n options: TestLayerOptions = {},\n): Layer.Layer<AssistantTestServices, never, TestContextService> => {\n const resolvedModel: DXN.DXN =\n options.model ??\n (options.aiServicePreset === 'ollama'\n ? DXN.make('com.openai.model.gpt-oss-20b.default')\n : DXN.make('com.anthropic.model.claude-opus-5.default'));\n\n // The catalog's shared model ids need a provider to resolve; pair the resolved model with the\n // provider its preset registers a resolver for.\n const resolvedProvider: DXN.DXN =\n options.provider ?? (options.aiServicePreset === 'ollama' ? Provider.ollama.id : Provider.edge.id);\n\n const agentOptions: AgentServiceRuntime.Options = { ...options.agent };\n agentOptions.defaultModel ??= resolvedModel;\n agentOptions.provider ??= resolvedProvider;\n\n // The resolver materialises `HarnessService` (Tier B needs `ProcessManager.Service`), but\n // `ProcessManager.layer` requires the `ServiceResolver` — a construction cycle. Resolve it by\n // sharing a late-bound holder: the resolver reads the manager lazily (only at resolution time,\n // when the manager exists), and a downstream layer fills the holder once it is built.\n const processManagerHolder: ProcessManagerHolder = {};\n const agentServiceHolder: AgentServiceHolder = {};\n\n return Layer.empty.pipe(\n // Captures must sit above the layers they read (a provideMerge chain feeds upward).\n Layer.provideMerge(captureAgentService(agentServiceHolder)),\n Layer.provideMerge(ProcessOperationInvoker.layer),\n Layer.provideMerge(AgentServiceRuntime.layer(agentOptions)),\n Layer.provideMerge(UnifiedProcessManager.layer),\n // A local test stack has no EDGE, so both the manager's remote half and `location: 'edge'` see\n // nothing.\n Layer.provideMerge(RemoteProcessManager.layerNoop),\n Layer.provideMerge(RemoteTraceMonitor.layerNoop),\n Layer.provideMerge(Trace.testTraceService({ meta: { processName: 'test' } })),\n // Order matters: in a `provideMerge` chain each layer's *requirements* are satisfied only by\n // layers added later (whose outputs feed it). `captureProcessManager` needs the manager, the\n // manager needs the `ServiceResolver`, and the resolver needs nothing (it reads the manager via\n // the holder), so they must appear in exactly this order.\n Layer.provideMerge(captureProcessManager(processManagerHolder)),\n Layer.provideMerge(ProcessManager.layer({ idGenerator: ProcessManager.SequentialIdGenerator })),\n Layer.provideMerge(AssistantTestServiceResolverLayer(options, processManagerHolder, agentServiceHolder)),\n Layer.provideMerge(AiService.languageModel(DXN.getName(resolvedModel), { provider: resolvedProvider })),\n Layer.provideMerge(AssistantTestTracingLayer(options.tracing ?? 'noop')),\n Layer.provideMerge(\n options.aiService ??\n TestAiService({\n preset: options.aiServicePreset,\n disableMemoization: options.disableLlmMemoization,\n dynamicValuePatterns: options.dynamicValuePatterns,\n }),\n ),\n Layer.provideMerge(AssistantTestBaseLayer(options)),\n Layer.orDie,\n );\n};\n\n/** Late-bound reference to the {@link ProcessManager.Service}, filled once the manager is built. */\ninterface ProcessManagerHolder {\n current?: Context.Service.Shape<typeof ProcessManager.Service>;\n}\n\n/** Late-bound reference to the {@link AgentService.AgentService}, filled once the service is built. */\ninterface AgentServiceHolder {\n current?: Context.Service.Shape<typeof AgentService.AgentService>;\n}\n\n/** An {@link AgentService.AgentService} that forwards to the holder's, so it can be handed out before that exists. */\nconst lateAgentService = (holder: AgentServiceHolder): Context.Service.Shape<typeof AgentService.AgentService> => ({\n getSession: (chat, options) =>\n Effect.suspend(() =>\n holder.current\n ? holder.current.getSession(chat, options)\n : Effect.die(new Error('AgentService is not built yet.')),\n ),\n hydrate: () =>\n Effect.suspend(() =>\n holder.current ? holder.current.hydrate() : Effect.die(new Error('AgentService is not built yet.')),\n ),\n});\n\n/** Fills the {@link AgentServiceHolder}, letting the resolver serve operations that relay into agent sessions. */\nconst captureAgentService = (holder: AgentServiceHolder): Layer.Layer<never, never, AgentService.AgentService> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n holder.current = yield* AgentService.AgentService;\n }),\n );\n\n/** Fills the {@link ProcessManagerHolder} once the manager is available, breaking the build cycle. */\nconst captureProcessManager = (holder: ProcessManagerHolder): Layer.Layer<never, never, ProcessManager.Service> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n holder.current = yield* ProcessManager.Service;\n }),\n );\n\n/**\n * Service resolver for testing.\n */\nexport const AssistantTestServiceResolverLayer = (\n { extraServices = Layer.empty }: Pick<TestLayerOptions, 'extraServices'>,\n processManagerHolder: ProcessManagerHolder,\n agentServiceHolder: AgentServiceHolder = {},\n) =>\n Layer.effect(\n ServiceResolver.ServiceResolver,\n Effect.gen(function* () {\n const services = yield* Effect.context<Database.Service>().pipe(\n Effect.map(Context.pick(Database.Service)),\n Effect.map(Layer.succeedContext),\n );\n\n const { db } = yield* Database.Service;\n\n // v4 dropped `Layer.toRuntime`; a built layer is its service context. The agent service is built\n // after the resolver (it needs it), so extra services reach it through the same late-bound holder.\n const extraServicesContext = yield* Layer.build(\n extraServices.pipe(\n Layer.provide(Layer.succeed(AgentService.AgentService, lateAgentService(agentServiceHolder))),\n ),\n );\n\n return ServiceResolver.compose(\n ServiceResolver.succeed(Harness.HarnessService, (context) =>\n Effect.gen(function* () {\n if (!context.conversation) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(Harness.HarnessService.key));\n }\n // Read the manager lazily: the resolver is invoked at spawn time, by which point the\n // holder has been filled (see the construction-cycle note in `AssistantTestLayer`).\n const processManager = processManagerHolder.current;\n if (!processManager) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(ProcessManager.Service.key));\n }\n const runtime = yield* Effect.context<Database.Service>();\n return yield* Harness.make({ conversation: context.conversation, processManager, runtime });\n }).pipe(Effect.provide(services)),\n ),\n // As the app's client contributes it: operations that look an object up across spaces need it.\n ServiceResolver.succeed(Hypergraph.Service, () => Effect.succeed(Hypergraph.makeService(db.graph))),\n ServiceResolver.succeed(AgentService.AgentService, () =>\n Effect.gen(function* () {\n // Read lazily (like the process manager): filled by `captureAgentService` before any\n // operation resolution runs.\n const agentService = agentServiceHolder.current;\n if (!agentService) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(AgentService.key));\n }\n return agentService;\n }),\n ),\n yield* ServiceResolver.fromRequirements(\n Database.Service,\n OpaqueToolkit.OpaqueToolkitProvider,\n AiService.AiService,\n Registry.Service,\n Credential.CredentialsService,\n ),\n ServiceResolver.fromContext(extraServicesContext),\n );\n }),\n );\n\n/**\n * Only storage + registry.\n */\nexport const AssistantTestBaseLayer = ({\n operationHandlers = [],\n toolkits = [],\n types = [],\n credentials = [],\n skills = [],\n}: Pick<TestLayerOptions, 'operationHandlers' | 'toolkits' | 'types' | 'skills' | 'tracing' | 'credentials'>) => {\n const toolkit = OpaqueToolkit.merge(...toolkits);\n const operationHandlersSet = Array.isArray(operationHandlers)\n ? OperationHandlerSet.merge(...operationHandlers)\n : operationHandlers;\n types.push(\n Skill.Skill,\n Instructions.Instructions,\n Operation.PersistentOperation,\n Feed.Feed,\n // The agent process runs on a chat, so every session — bare ones included — persists one.\n Chat.Chat,\n Trigger.Trigger,\n Tag.Tag,\n Alarm.Alarm,\n );\n types = Array.dedupeWith(types, (a, b) => Type.getTypename(a) === Type.getTypename(b));\n\n return Layer.empty.pipe(\n // A skill referenced by its registry URI resolves through the DATABASE's registry (production\n // wires that up via plugin-instructions' `RegistrySync`), which is not the `Registry.Service`\n // seeded below — so a seeded skill has to land in both, or such a ref silently resolves to\n // nothing and the conversation loses the skill.\n Layer.provideMerge(seedDatabaseRegistry(skills)),\n Layer.provideMerge(\n TestDatabaseLayer({\n spaceKey: 'fixed',\n types,\n }),\n ),\n Layer.provideMerge(configuredCredentialsLayer(credentials)),\n Layer.provideMerge(\n Layer.effect(\n Registry.Service,\n Effect.gen(function* () {\n const handlerSet = yield* OperationHandlerSet.OperationHandlerProvider;\n const registry = yield* Registry.Service;\n const handlers = yield* handlerSet.handlers;\n registry.add(Operation.serializable(handlers));\n return registry;\n }),\n ),\n ),\n Layer.provideMerge(registryLayer({ initial: skills })),\n Layer.provideMerge(OpaqueToolkit.providerLayer(toolkit)),\n Layer.provideMerge(OperationHandlerSet.provide(operationHandlersSet)),\n Layer.provideMerge(KeyValueStore.layerMemory),\n Layer.provideMerge(AtomRegistry.layer),\n Layer.orDie,\n );\n};\n\n/** Registers the seeded skills with the database's registry, so their registry-URI refs resolve. */\nconst seedDatabaseRegistry = (skills: readonly Skill.Skill[]): Layer.Layer<never, never, Database.Service> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n if (skills.length === 0) {\n return;\n }\n const { db } = yield* Database.Service;\n db.registry.add(skills);\n }),\n );\n\nconst AssistantTestTracingLayer = (\n mode: 'noop' | 'console' | 'pretty' | 'feed',\n): Layer.Layer<FeedTraceSink.FeedTraceSink | Trace.TraceSink, never, Database.Service> =>\n Match.value(mode).pipe(\n Match.when('noop', () => Layer.mergeAll(Trace.layerNoop, FeedTraceSink.layerNoop)),\n Match.when('console', () => Layer.mergeAll(Trace.layerConsole, FeedTraceSink.layerNoop)),\n Match.when('pretty', () => Layer.mergeAll(traceSinkPrettyLayer(), FeedTraceSink.layerNoop)),\n Match.when('feed', () => FeedTraceSink.layerLiveWithDirectSink),\n Match.exhaustive,\n );\n\ninterface TestLayerWithTriggersOptions extends TestLayerOptions {}\n\nexport type AssistantTestServicesWithTriggers = AssistantTestServices | TriggerDispatcher | TriggerStateStore;\n\nexport const AssistantTestLayerWithTriggers = (\n options: TestLayerWithTriggersOptions,\n): Layer.Layer<AssistantTestServicesWithTriggers, never, TestContextService> =>\n // `Layer.provideMerge` (not `Layer.mergeAll`) at each step: `mergeAll` unions requirements without\n // letting sibling layers discharge one another, so `TriggerDispatcher`'s own dependency on\n // `TriggerStateStore`/`ProcessManager.Service`/`Database.Service` needs threading explicitly.\n TriggerDispatcher.layer({ timeControl: 'manual', startingTime: new Date('2025-09-05T15:01:00.000Z') }).pipe(\n Layer.provide(AtomRegistry.layer),\n Layer.provideMerge(TriggerStateStore.layerMemory),\n Layer.provideMerge(AssistantTestLayer(options)),\n );\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Scope from 'effect/Scope';\nimport * as Stream from 'effect/Stream';\n\nimport type * as AgentService from '@dxos/compute/AgentService';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Feed, Filter, Obj } from '@dxos/echo';\nimport { BaseError, type BaseErrorOptions } from '@dxos/errors';\nimport { Message } from '@dxos/types';\n\n/**\n * Buffered view of a session's ephemeral block events — the headless equivalent of what the chat\n * UI renders while a request streams.\n */\nexport interface EphemeralCollector {\n /** Snapshot of `Trace.PartialBlock` payloads observed so far, in arrival order. */\n partialBlocks: () => readonly Trace.PayloadType<typeof Trace.PartialBlock>[];\n /** Snapshot of `Trace.CompleteBlock` payloads observed so far, in arrival order. */\n completeBlocks: () => readonly Trace.PayloadType<typeof Trace.CompleteBlock>[];\n}\n\n/**\n * Forks a collector over {@link AgentService.Session.subscribeEphemeral} so a test can assert the\n * streaming path (partial → complete blocks) without a UI. The fork is scoped: use with\n * `it.effect` (or an explicit scope) so the subscription is interrupted on test close.\n */\nexport const collectEphemeral = (\n session: AgentService.Session,\n): Effect.Effect<EphemeralCollector, never, Scope.Scope> =>\n Effect.gen(function* () {\n const partial: Trace.PayloadType<typeof Trace.PartialBlock>[] = [];\n const complete: Trace.PayloadType<typeof Trace.CompleteBlock>[] = [];\n yield* session.subscribeEphemeral().pipe(\n Stream.runForEach((message) =>\n Effect.sync(() => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.PartialBlock, event)) {\n partial.push(event.data);\n } else if (Trace.isOfType(Trace.CompleteBlock, event)) {\n complete.push(event.data);\n }\n }\n }),\n ),\n Effect.forkScoped,\n );\n\n return {\n partialBlocks: () => [...partial],\n completeBlocks: () => [...complete],\n };\n });\n\nexport class WaitForMessageTimeoutError extends BaseError.extend('WaitForMessageTimeoutError') {\n constructor(timeout: number, options?: Omit<BaseErrorOptions, 'context'>) {\n super({\n message: `Timed out after ${timeout}ms waiting for a matching feed message.`,\n context: { timeout },\n ...options,\n });\n }\n}\n\nexport interface WaitForMessageOptions {\n /** Overall deadline in milliseconds. @default 10_000 */\n timeout?: number;\n /** Poll interval in milliseconds. @default 100 */\n interval?: number;\n}\n\n/**\n * Polls the conversation feed until a message matches. Covers the gap left by\n * `Session.waitForCompletion`, which settles when the *turn* completes — background sub-agents\n * report back later, out of band. Polls on the real clock (not the Effect `TestClock`), so it works\n * under `it.effect` and `it.effect` alike.\n */\nexport const waitForMessage = (\n feed: Feed.Feed,\n predicate: (message: Message.Message) => boolean,\n { timeout = 10_000, interval = 100 }: WaitForMessageOptions = {},\n): Effect.Effect<Message.Message, WaitForMessageTimeoutError, Database.Service> =>\n Effect.gen(function* () {\n const deadline = Date.now() + timeout;\n do {\n const items = yield* Feed.query(feed, Filter.type(Message.Message)).run;\n const match = items.filter(Obj.instanceOf(Message.Message)).find(predicate);\n if (match) {\n return match;\n }\n yield* Effect.promise(() => new Promise((resolve) => setTimeout(resolve, interval)));\n } while (Date.now() < deadline);\n\n return yield* Effect.fail(new WaitForMessageTimeoutError(timeout));\n });\n\n/** Convenience predicate: any block's text content contains the substring. */\nexport const messageTextIncludes =\n (needle: string) =>\n (message: Message.Message): boolean =>\n Message.extractText(message).includes(needle);\n","//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Context from 'effect/Context';\nimport * as Deferred from 'effect/Deferred';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Queue from 'effect/Queue';\n\nimport { log } from '@dxos/log';\nimport { Organization } from '@dxos/types';\n\n//\n// Test data.\n//\n\nexport const getTestData = () => ({\n organizations: [\n Organization.make({\n name: 'Cyberdyne Systems',\n website: 'https://cyberdyne.com',\n }),\n Organization.make({\n name: 'Acme Robotics',\n website: 'https://acmerobotics.example',\n }),\n Organization.make({\n name: 'Globex Research',\n website: 'https://globex.example',\n }),\n ],\n research: {\n 'https://cyberdyne.com': `\n Cyberdyne Systems is a company that builds AI agents.\n They are based in San Francisco, California.\n They were founded in 1984.\n They are a public company.\n They are listed on the NASDAQ under the symbol CYBR.\n They are a member of the S&P 500 index.\n `,\n 'https://acmerobotics.example': `\n Acme Robotics designs industrial automation and collaborative robots.\n They are headquartered in Austin, Texas.\n They were founded in 2010.\n They serve manufacturing and logistics customers worldwide.\n `,\n 'https://globex.example': `\n Globex Research runs applied R&D labs focused on materials science and energy storage.\n They are based in Cambridge, Massachusetts.\n They partner with universities and government grants programs.\n Their flagship product line is solid-state battery prototypes for EVs.\n `,\n } as Record<string, string>,\n});\n\nexport interface Task {\n id: string;\n state: 'pending' | 'completed' | 'interrupted';\n website: string;\n deferred: Deferred.Deferred<string>;\n}\n\nexport interface Service {\n getTasks: () => readonly Task[];\n research: (website: string) => Effect.Effect<string>;\n waitForTaskToAppear: () => Effect.Effect<void>;\n completeOneTask: () => Effect.Effect<void>;\n completeAllTasks: () => Effect.Effect<void>;\n}\n\nexport class ResearchService extends Context.Service<ResearchService, Service>()(\n '@dxos/functions-runtime/testing/ResearchService',\n) {}\n\nexport const layer = Layer.effect(\n ResearchService,\n Effect.gen(function* () {\n const taskSignal = yield* Queue.unbounded<void>();\n const tasks: Task[] = [];\n const complete = (task: Task) =>\n Effect.gen(function* () {\n log.info('complete research', { id: task.id, website: task.website });\n task.state = 'completed';\n const result = getTestData().research[task.website];\n if (!result) {\n return yield* Effect.die(new Error(`No research found for ${task.website}`));\n }\n yield* Deferred.succeed(task.deferred, result);\n });\n\n return ResearchService.of({\n getTasks: () => tasks,\n research: (website: string) =>\n Effect.gen(function* () {\n const id = crypto.randomUUID();\n const task: Task = { id, state: 'pending', website, deferred: yield* Deferred.make<string>() };\n log.info('start research', { id, website });\n tasks.push(task);\n yield* Queue.offer(taskSignal, undefined);\n return yield* Deferred.await(task.deferred).pipe(\n Effect.onInterrupt(() =>\n Effect.sync(() => {\n log.info('interrupt research', { id, website: task.website });\n task.state = 'interrupted';\n }),\n ),\n );\n }),\n waitForTaskToAppear: () =>\n Effect.gen(function* () {\n while (true) {\n const task = tasks.find((t) => t.state === 'pending');\n if (task) {\n return;\n }\n yield* Queue.take(taskSignal);\n }\n }),\n completeOneTask: () =>\n Effect.gen(function* () {\n const task = tasks.find((t) => t.state === 'pending');\n if (!task) {\n return;\n }\n yield* complete(task);\n }),\n completeAllTasks: () =>\n Effect.gen(function* () {\n while (true) {\n const task = tasks.find((t) => t.state === 'pending');\n if (!task) {\n return;\n }\n yield* complete(task);\n }\n }),\n });\n }),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"testing.mjs","names":["AgentServiceRuntime.layer"],"sources":["../../src/testing/trace-pretty-print.ts","../../src/testing/assistant-test-layer.ts","../../src/testing/test-agent.ts","../../src/testing/ResearchService.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { ConsolePrinter } from '@dxos/ai';\nimport { FeedTraceSink } from '@dxos/compute-runtime';\nimport * as Process from '@dxos/compute/Process';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Filter, Query } from '@dxos/echo';\n\n/**\n * Pretty-prints assistant trace messages to stdout (Trace.CompleteBlock, process spawn/exit).\n */\nexport const prettyPrintTraceMessage = (message: Trace.Message): void => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.CompleteBlock, event)) {\n const tag = message.meta.processName ?? `${message.meta.pid ?? 'unknown'}`;\n console.log(`[${tag}] ${event.data.role.toUpperCase()}`);\n new ConsolePrinter({ tag }).printContentBlock(event.data.block);\n } else if (Trace.isOfType(Process.SpawnedEvent, event)) {\n console.log(`[${message.meta.pid}] Process spawned: ${message.meta.processName}`);\n } else if (Trace.isOfType(Process.ExitedEvent, event)) {\n console.log(`[${message.meta.pid}] Process exited: ${event.data.outcome}`);\n }\n }\n};\n\n/** {@link Trace.TraceSink} layer that mirrors {@link AssistantTestLayer}'s `tracing: 'pretty'` mode. */\nexport const traceSinkPrettyLayer = (): Layer.Layer<Trace.TraceSink> =>\n Layer.succeed(Trace.TraceSink, {\n write: prettyPrintTraceMessage,\n });\n\n/**\n * Subscribes to the space trace feed and pretty-prints newly appended messages.\n * Returns an unsubscribe function. Requires ambient {@link Database.Service}.\n */\nexport const traceFeedPrettyPrintSubscription = Effect.gen(function* () {\n const feed = yield* FeedTraceSink.getOrCreateTraceFeed();\n const queryResult = yield* Database.query(Query.select(Filter.type(Trace.Message)).from(feed));\n const seen = new Set((yield* Effect.promise(() => queryResult.run())).map((message) => message.id));\n\n return queryResult.subscribe((result) => {\n for (const message of result.results) {\n if (seen.has(message.id)) {\n continue;\n }\n seen.add(message.id);\n prettyPrintTraceMessage(message);\n }\n });\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Array from 'effect/Array';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Match from 'effect/Match';\nimport * as KeyValueStore from 'effect/persistence/KeyValueStore';\nimport * as AtomRegistry from 'effect/reactivity/AtomRegistry';\n\nimport { AiService, OpaqueToolkit, Provider } from '@dxos/ai';\nimport { type AiServicePreset, TestAiService } from '@dxos/ai/testing';\nimport { Alarm, Harness } from '@dxos/assistant';\nimport * as Chat from '@dxos/assistant/Chat';\nimport {\n FeedTraceSink,\n ProcessManager,\n ProcessOperationInvoker,\n RemoteProcessManager,\n RemoteTraceMonitor,\n TriggerDispatcher,\n TriggerStateStore,\n UnifiedProcessManager,\n configuredCredentialsLayer,\n} from '@dxos/compute-runtime';\nimport { TestDatabaseLayer } from '@dxos/compute-runtime/testing';\nimport * as AgentService from '@dxos/compute/AgentService';\nimport * as Credential from '@dxos/compute/Credential';\nimport * as Instructions from '@dxos/compute/Instructions';\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\nimport * as Process from '@dxos/compute/Process';\nimport * as ServiceResolver from '@dxos/compute/ServiceResolver';\nimport * as Skill from '@dxos/compute/Skill';\nimport * as Trace from '@dxos/compute/Trace';\nimport * as Trigger from '@dxos/compute/Trigger';\nimport { Database, Feed, Hypergraph, Registry, Tag, Type } from '@dxos/echo';\nimport { registryLayer } from '@dxos/echo-client';\nimport { type TestContextService } from '@dxos/effect/testing';\nimport { DXN } from '@dxos/keys';\n\nimport { AgentService as AgentServiceRuntime } from '../agent-service/index.ts';\nimport { traceSinkPrettyLayer } from './trace-pretty-print.ts';\n\ninterface TestLayerOptions {\n aiServicePreset?: AiServicePreset;\n\n /**\n * Overrides the AI service entirely (e.g. a scripted model for deterministic e2e tests).\n * When set, `aiServicePreset` and `disableLlmMemoization` are ignored.\n */\n aiService?: Layer.Layer<AiService.AiService>;\n model?: DXN.DXN;\n /** Provider the model resolves through; defaults to `ollama` for the ollama preset, else `edge`. */\n provider?: DXN.DXN;\n operationHandlers?: OperationHandlerSet.OperationHandlerSet | OperationHandlerSet.OperationHandlerSet[];\n toolkits?: OpaqueToolkit.OpaqueToolkit[];\n types?: Type.AnyEntity[];\n skills?: Skill.Skill[];\n credentials?: Credential.ServiceCredential[];\n\n /**\n * Tracing configuration.\n * - `'feed'` persists trace events to a FeedTraceSink (queryable from the database).\n * @default 'noop'\n */\n tracing?: 'noop' | 'console' | 'pretty' | 'feed';\n\n disableLlmMemoization?: boolean;\n\n /**\n * Patterns matching run-specific values (e.g. timestamps derived from TestClock) that should be\n * canonicalized for memoized-conversation matching. Forwarded to `TestAiService`. Opt-in.\n */\n dynamicValuePatterns?: readonly RegExp[];\n\n /**\n * Options for the agent process (system prompt, tool backgrounding, delegation strategy, etc.).\n * The model defaults to the resolved test-layer model when not set here.\n */\n agent?: AgentServiceRuntime.Options;\n\n /**\n * Extra services to make available in the service resolver.\n * Operations can depend on those services. They may themselves require the {@link AgentService.AgentService}\n * (e.g. a service that wakes other conversations), which is served to them once it is built.\n */\n extraServices?: Layer.Layer<never, never, AgentService.AgentService>;\n}\n\nexport type AssistantTestServices =\n | LanguageModel.LanguageModel\n | Credential.CredentialsService\n | AgentService.AgentService\n | AiService.AiService\n | Database.Service\n | Registry.Service\n | OpaqueToolkit.OpaqueToolkitProvider\n | Operation.Service\n | ProcessManager.Service\n | RemoteProcessManager.Service\n | ProcessOperationInvoker.Service\n | Process.ManagerService\n | AtomRegistry.AtomRegistry\n | OperationHandlerSet.OperationHandlerProvider\n | KeyValueStore.KeyValueStore\n | ServiceResolver.ServiceResolver\n | Trace.TraceService\n | Trace.TraceSink\n | FeedTraceSink.FeedTraceSink;\n\nexport const AssistantTestLayer = (\n options: TestLayerOptions = {},\n): Layer.Layer<AssistantTestServices, never, TestContextService> => {\n const resolvedModel: DXN.DXN =\n options.model ??\n (options.aiServicePreset === 'ollama'\n ? DXN.make('com.openai.model.gpt-oss-20b.default')\n : DXN.make('com.anthropic.model.claude-opus-5.default'));\n\n // The catalog's shared model ids need a provider to resolve; pair the resolved model with the\n // provider its preset registers a resolver for.\n const resolvedProvider: DXN.DXN =\n options.provider ?? (options.aiServicePreset === 'ollama' ? Provider.ollama.id : Provider.edge.id);\n\n const agentOptions: AgentServiceRuntime.Options = { ...options.agent };\n agentOptions.defaultModel ??= resolvedModel;\n agentOptions.provider ??= resolvedProvider;\n\n // The resolver materialises `HarnessService` (Tier B needs `ProcessManager.Service`), but\n // `ProcessManager.layer` requires the `ServiceResolver` — a construction cycle. Resolve it by\n // sharing a late-bound holder: the resolver reads the manager lazily (only at resolution time,\n // when the manager exists), and a downstream layer fills the holder once it is built.\n const processManagerHolder: ProcessManagerHolder = {};\n const agentServiceHolder: AgentServiceHolder = {};\n\n return Layer.empty.pipe(\n // Captures must sit above the layers they read (a provideMerge chain feeds upward).\n Layer.provideMerge(captureAgentService(agentServiceHolder)),\n Layer.provideMerge(ProcessOperationInvoker.layer),\n Layer.provideMerge(AgentServiceRuntime.layer(agentOptions)),\n Layer.provideMerge(UnifiedProcessManager.layer),\n // A local test stack has no EDGE, so both the manager's remote half and `location: 'edge'` see\n // nothing.\n Layer.provideMerge(RemoteProcessManager.layerNoop),\n Layer.provideMerge(RemoteTraceMonitor.layerNoop),\n Layer.provideMerge(Trace.testTraceService({ meta: { processName: 'test' } })),\n // Order matters: in a `provideMerge` chain each layer's *requirements* are satisfied only by\n // layers added later (whose outputs feed it). `captureProcessManager` needs the manager, the\n // manager needs the `ServiceResolver`, and the resolver needs nothing (it reads the manager via\n // the holder), so they must appear in exactly this order.\n Layer.provideMerge(captureProcessManager(processManagerHolder)),\n Layer.provideMerge(ProcessManager.layer({ idGenerator: ProcessManager.SequentialIdGenerator })),\n Layer.provideMerge(AssistantTestServiceResolverLayer(options, processManagerHolder, agentServiceHolder)),\n Layer.provideMerge(AiService.languageModel(DXN.getName(resolvedModel), { provider: resolvedProvider })),\n Layer.provideMerge(AssistantTestTracingLayer(options.tracing ?? 'noop')),\n Layer.provideMerge(\n options.aiService ??\n TestAiService({\n preset: options.aiServicePreset,\n disableMemoization: options.disableLlmMemoization,\n dynamicValuePatterns: options.dynamicValuePatterns,\n }),\n ),\n Layer.provideMerge(AssistantTestBaseLayer(options)),\n Layer.orDie,\n );\n};\n\n/** Late-bound reference to the {@link ProcessManager.Service}, filled once the manager is built. */\ninterface ProcessManagerHolder {\n current?: Context.Service.Shape<typeof ProcessManager.Service>;\n}\n\n/** Late-bound reference to the {@link AgentService.AgentService}, filled once the service is built. */\ninterface AgentServiceHolder {\n current?: Context.Service.Shape<typeof AgentService.AgentService>;\n}\n\n/** An {@link AgentService.AgentService} that forwards to the holder's, so it can be handed out before that exists. */\nconst lateAgentService = (holder: AgentServiceHolder): Context.Service.Shape<typeof AgentService.AgentService> => ({\n getSession: (chat, options) =>\n Effect.suspend(() =>\n holder.current\n ? holder.current.getSession(chat, options)\n : Effect.die(new Error('AgentService is not built yet.')),\n ),\n hydrate: () =>\n Effect.suspend(() =>\n holder.current ? holder.current.hydrate() : Effect.die(new Error('AgentService is not built yet.')),\n ),\n});\n\n/** Fills the {@link AgentServiceHolder}, letting the resolver serve operations that relay into agent sessions. */\nconst captureAgentService = (holder: AgentServiceHolder): Layer.Layer<never, never, AgentService.AgentService> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n holder.current = yield* AgentService.AgentService;\n }),\n );\n\n/** Fills the {@link ProcessManagerHolder} once the manager is available, breaking the build cycle. */\nconst captureProcessManager = (holder: ProcessManagerHolder): Layer.Layer<never, never, ProcessManager.Service> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n holder.current = yield* ProcessManager.Service;\n }),\n );\n\n/**\n * Service resolver for testing.\n */\nexport const AssistantTestServiceResolverLayer = (\n { extraServices = Layer.empty }: Pick<TestLayerOptions, 'extraServices'>,\n processManagerHolder: ProcessManagerHolder,\n agentServiceHolder: AgentServiceHolder = {},\n) =>\n Layer.effect(\n ServiceResolver.ServiceResolver,\n Effect.gen(function* () {\n const services = yield* Effect.context<Database.Service>().pipe(\n Effect.map(Context.pick(Database.Service)),\n Effect.map(Layer.succeedContext),\n );\n\n const { db } = yield* Database.Service;\n\n // v4 dropped `Layer.toRuntime`; a built layer is its service context. The agent service is built\n // after the resolver (it needs it), so extra services reach it through the same late-bound holder.\n const extraServicesContext = yield* Layer.build(\n extraServices.pipe(\n Layer.provide(Layer.succeed(AgentService.AgentService, lateAgentService(agentServiceHolder))),\n ),\n );\n\n return ServiceResolver.compose(\n ServiceResolver.succeed(Harness.HarnessService, (context) =>\n Effect.gen(function* () {\n if (!context.conversation) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(Harness.HarnessService.key));\n }\n // Read the manager lazily: the resolver is invoked at spawn time, by which point the\n // holder has been filled (see the construction-cycle note in `AssistantTestLayer`).\n const processManager = processManagerHolder.current;\n if (!processManager) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(ProcessManager.Service.key));\n }\n const runtime = yield* Effect.context<Database.Service>();\n return yield* Harness.make({ conversation: context.conversation, processManager, runtime });\n }).pipe(Effect.provide(services)),\n ),\n // As the app's client contributes it: operations that look an object up across spaces need it.\n ServiceResolver.succeed(Hypergraph.Service, () => Effect.succeed(Hypergraph.makeService(db.graph))),\n ServiceResolver.succeed(AgentService.AgentService, () =>\n Effect.gen(function* () {\n // Read lazily (like the process manager): filled by `captureAgentService` before any\n // operation resolution runs.\n const agentService = agentServiceHolder.current;\n if (!agentService) {\n return yield* Effect.fail(new ServiceResolver.ServiceNotAvailableError(AgentService.key));\n }\n return agentService;\n }),\n ),\n yield* ServiceResolver.fromRequirements(\n Database.Service,\n OpaqueToolkit.OpaqueToolkitProvider,\n AiService.AiService,\n Registry.Service,\n Credential.CredentialsService,\n ),\n ServiceResolver.fromContext(extraServicesContext),\n );\n }),\n );\n\n/**\n * Only storage + registry.\n */\nexport const AssistantTestBaseLayer = ({\n operationHandlers = [],\n toolkits = [],\n types = [],\n credentials = [],\n skills = [],\n}: Pick<TestLayerOptions, 'operationHandlers' | 'toolkits' | 'types' | 'skills' | 'tracing' | 'credentials'>) => {\n const toolkit = OpaqueToolkit.merge(...toolkits);\n const operationHandlersSet = Array.isArray(operationHandlers)\n ? OperationHandlerSet.merge(...operationHandlers)\n : operationHandlers;\n types.push(\n Skill.Skill,\n Instructions.Instructions,\n Operation.PersistentOperation,\n Feed.Feed,\n // The agent process runs on a chat, so every session — bare ones included — persists one.\n Chat.Chat,\n Trigger.Trigger,\n Tag.Tag,\n Alarm.Alarm,\n );\n types = Array.dedupeWith(types, (a, b) => Type.getTypename(a) === Type.getTypename(b));\n\n return Layer.empty.pipe(\n // A skill referenced by its registry URI resolves through the DATABASE's registry (production\n // wires that up via plugin-instructions' `RegistrySync`), which is not the `Registry.Service`\n // seeded below — so a seeded skill has to land in both, or such a ref silently resolves to\n // nothing and the conversation loses the skill.\n Layer.provideMerge(seedDatabaseRegistry(skills)),\n Layer.provideMerge(\n TestDatabaseLayer({\n spaceKey: 'fixed',\n types,\n }),\n ),\n Layer.provideMerge(configuredCredentialsLayer(credentials)),\n Layer.provideMerge(\n Layer.effect(\n Registry.Service,\n Effect.gen(function* () {\n const handlerSet = yield* OperationHandlerSet.OperationHandlerProvider;\n const registry = yield* Registry.Service;\n const handlers = yield* handlerSet.handlers;\n registry.add(Operation.serializable(handlers));\n return registry;\n }),\n ),\n ),\n Layer.provideMerge(registryLayer({ initial: skills })),\n Layer.provideMerge(OpaqueToolkit.providerLayer(toolkit)),\n Layer.provideMerge(OperationHandlerSet.provide(operationHandlersSet)),\n Layer.provideMerge(KeyValueStore.layerMemory),\n Layer.provideMerge(AtomRegistry.layer),\n Layer.orDie,\n );\n};\n\n/** Registers the seeded skills with the database's registry, so their registry-URI refs resolve. */\nconst seedDatabaseRegistry = (skills: readonly Skill.Skill[]): Layer.Layer<never, never, Database.Service> =>\n Layer.effectDiscard(\n Effect.gen(function* () {\n if (skills.length === 0) {\n return;\n }\n const { db } = yield* Database.Service;\n db.registry.add(skills);\n }),\n );\n\nconst AssistantTestTracingLayer = (\n mode: 'noop' | 'console' | 'pretty' | 'feed',\n): Layer.Layer<FeedTraceSink.FeedTraceSink | Trace.TraceSink, never, Database.Service> =>\n Match.value(mode).pipe(\n Match.when('noop', () => Layer.mergeAll(Trace.layerNoop, FeedTraceSink.layerNoop)),\n Match.when('console', () => Layer.mergeAll(Trace.layerConsole, FeedTraceSink.layerNoop)),\n Match.when('pretty', () => Layer.mergeAll(traceSinkPrettyLayer(), FeedTraceSink.layerNoop)),\n Match.when('feed', () => FeedTraceSink.layerLiveWithDirectSink),\n Match.exhaustive,\n );\n\ninterface TestLayerWithTriggersOptions extends TestLayerOptions {}\n\nexport type AssistantTestServicesWithTriggers = AssistantTestServices | TriggerDispatcher | TriggerStateStore;\n\nexport const AssistantTestLayerWithTriggers = (\n options: TestLayerWithTriggersOptions,\n): Layer.Layer<AssistantTestServicesWithTriggers, never, TestContextService> =>\n // `Layer.provideMerge` (not `Layer.mergeAll`) at each step: `mergeAll` unions requirements without\n // letting sibling layers discharge one another, so `TriggerDispatcher`'s own dependency on\n // `TriggerStateStore`/`ProcessManager.Service`/`Database.Service` needs threading explicitly.\n TriggerDispatcher.layer({ timeControl: 'manual', startingTime: new Date('2025-09-05T15:01:00.000Z') }).pipe(\n Layer.provide(AtomRegistry.layer),\n Layer.provideMerge(TriggerStateStore.layerMemory),\n Layer.provideMerge(AssistantTestLayer(options)),\n );\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport type * as Scope from 'effect/Scope';\nimport * as Stream from 'effect/Stream';\n\nimport type * as AgentService from '@dxos/compute/AgentService';\nimport * as Trace from '@dxos/compute/Trace';\nimport { Database, Feed, Filter, Obj } from '@dxos/echo';\nimport { BaseError, type BaseErrorOptions } from '@dxos/errors';\nimport { Message } from '@dxos/types';\n\n/**\n * Buffered view of a session's ephemeral block events — the headless equivalent of what the chat\n * UI renders while a request streams.\n */\nexport interface EphemeralCollector {\n /** Snapshot of `Trace.PartialBlock` payloads observed so far, in arrival order. */\n partialBlocks: () => readonly Trace.PayloadType<typeof Trace.PartialBlock>[];\n /** Snapshot of `Trace.CompleteBlock` payloads observed so far, in arrival order. */\n completeBlocks: () => readonly Trace.PayloadType<typeof Trace.CompleteBlock>[];\n}\n\n/**\n * Forks a collector over {@link AgentService.Session.subscribeEphemeral} so a test can assert the\n * streaming path (partial → complete blocks) without a UI. The fork is scoped: use with\n * `it.effect` (or an explicit scope) so the subscription is interrupted on test close.\n */\nexport const collectEphemeral = (\n session: AgentService.Session,\n): Effect.Effect<EphemeralCollector, never, Scope.Scope> =>\n Effect.gen(function* () {\n const partial: Trace.PayloadType<typeof Trace.PartialBlock>[] = [];\n const complete: Trace.PayloadType<typeof Trace.CompleteBlock>[] = [];\n yield* session.subscribeEphemeral().pipe(\n Stream.runForEach((message) =>\n Effect.sync(() => {\n for (const event of message.events) {\n if (Trace.isOfType(Trace.PartialBlock, event)) {\n partial.push(event.data);\n } else if (Trace.isOfType(Trace.CompleteBlock, event)) {\n complete.push(event.data);\n }\n }\n }),\n ),\n Effect.forkScoped,\n );\n\n return {\n partialBlocks: () => [...partial],\n completeBlocks: () => [...complete],\n };\n });\n\nexport class WaitForMessageTimeoutError extends BaseError.extend('WaitForMessageTimeoutError') {\n constructor(timeout: number, options?: Omit<BaseErrorOptions, 'context'>) {\n super({\n message: `Timed out after ${timeout}ms waiting for a matching feed message.`,\n context: { timeout },\n ...options,\n });\n }\n}\n\nexport interface WaitForMessageOptions {\n /** Overall deadline in milliseconds. @default 10_000 */\n timeout?: number;\n /** Poll interval in milliseconds. @default 100 */\n interval?: number;\n}\n\n/**\n * Polls the conversation feed until a message matches. Covers the gap left by\n * `Session.waitForCompletion`, which settles when the *turn* completes — background sub-agents\n * report back later, out of band. Polls on the real clock (not the Effect `TestClock`), so it works\n * under `it.effect` and `it.effect` alike.\n */\nexport const waitForMessage = (\n feed: Feed.Feed,\n predicate: (message: Message.Message) => boolean,\n { timeout = 10_000, interval = 100 }: WaitForMessageOptions = {},\n): Effect.Effect<Message.Message, WaitForMessageTimeoutError, Database.Service> =>\n Effect.gen(function* () {\n const deadline = Date.now() + timeout;\n do {\n const items = yield* Feed.query(feed, Filter.type(Message.Message)).run;\n const match = items.filter(Obj.instanceOf(Message.Message)).find(predicate);\n if (match) {\n return match;\n }\n yield* Effect.promise(() => new Promise((resolve) => setTimeout(resolve, interval)));\n } while (Date.now() < deadline);\n\n return yield* Effect.fail(new WaitForMessageTimeoutError(timeout));\n });\n\n/** Convenience predicate: any block's text content contains the substring. */\nexport const messageTextIncludes =\n (needle: string) =>\n (message: Message.Message): boolean =>\n Message.extractText(message).includes(needle);\n","//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Context from 'effect/Context';\nimport * as Deferred from 'effect/Deferred';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Queue from 'effect/Queue';\n\nimport { log } from '@dxos/log';\nimport { Organization } from '@dxos/types';\n\n//\n// Test data.\n//\n\nexport const getTestData = () => ({\n organizations: [\n Organization.make({\n name: 'Cyberdyne Systems',\n website: 'https://cyberdyne.com',\n }),\n Organization.make({\n name: 'Acme Robotics',\n website: 'https://acmerobotics.example',\n }),\n Organization.make({\n name: 'Globex Research',\n website: 'https://globex.example',\n }),\n ],\n research: {\n 'https://cyberdyne.com': `\n Cyberdyne Systems is a company that builds AI agents.\n They are based in San Francisco, California.\n They were founded in 1984.\n They are a public company.\n They are listed on the NASDAQ under the symbol CYBR.\n They are a member of the S&P 500 index.\n `,\n 'https://acmerobotics.example': `\n Acme Robotics designs industrial automation and collaborative robots.\n They are headquartered in Austin, Texas.\n They were founded in 2010.\n They serve manufacturing and logistics customers worldwide.\n `,\n 'https://globex.example': `\n Globex Research runs applied R&D labs focused on materials science and energy storage.\n They are based in Cambridge, Massachusetts.\n They partner with universities and government grants programs.\n Their flagship product line is solid-state battery prototypes for EVs.\n `,\n } as Record<string, string>,\n});\n\nexport interface Task {\n id: string;\n state: 'pending' | 'completed' | 'interrupted';\n website: string;\n deferred: Deferred.Deferred<string>;\n}\n\nexport interface Service {\n getTasks: () => readonly Task[];\n research: (website: string) => Effect.Effect<string>;\n waitForTaskToAppear: () => Effect.Effect<void>;\n completeOneTask: () => Effect.Effect<void>;\n completeAllTasks: () => Effect.Effect<void>;\n}\n\nexport class ResearchService extends Context.Service<ResearchService, Service>()(\n '@dxos/functions-runtime/testing/ResearchService',\n) {}\n\nexport const layer = Layer.effect(\n ResearchService,\n Effect.gen(function* () {\n const taskSignal = yield* Queue.unbounded<void>();\n const tasks: Task[] = [];\n const complete = (task: Task) =>\n Effect.gen(function* () {\n log.info('complete research', { id: task.id, website: task.website });\n task.state = 'completed';\n const result = getTestData().research[task.website];\n if (!result) {\n return yield* Effect.die(new Error(`No research found for ${task.website}`));\n }\n yield* Deferred.succeed(task.deferred, result);\n });\n\n return ResearchService.of({\n getTasks: () => tasks,\n research: (website: string) =>\n Effect.gen(function* () {\n const id = crypto.randomUUID();\n const task: Task = { id, state: 'pending', website, deferred: yield* Deferred.make<string>() };\n log.info('start research', { id, website });\n tasks.push(task);\n yield* Queue.offer(taskSignal, undefined);\n return yield* Deferred.await(task.deferred).pipe(\n Effect.onInterrupt(() =>\n Effect.sync(() => {\n log.info('interrupt research', { id, website: task.website });\n task.state = 'interrupted';\n }),\n ),\n );\n }),\n waitForTaskToAppear: () =>\n Effect.gen(function* () {\n while (true) {\n const task = tasks.find((t) => t.state === 'pending');\n if (task) {\n return;\n }\n yield* Queue.take(taskSignal);\n }\n }),\n completeOneTask: () =>\n Effect.gen(function* () {\n const task = tasks.find((t) => t.state === 'pending');\n if (!task) {\n return;\n }\n yield* complete(task);\n }),\n completeAllTasks: () =>\n Effect.gen(function* () {\n while (true) {\n const task = tasks.find((t) => t.state === 'pending');\n if (!task) {\n return;\n }\n yield* complete(task);\n }\n }),\n });\n }),\n);\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"AgentService.d.ts","sourceRoot":"","sources":["../../../../src/agent-service/AgentService.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAMtC,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAc,QAAQ,EAAQ,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAqB,MAAM,YAAY,CAAC;AAIpD,OAAO,EAAoD,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACnH,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,CAC1B,IAAI,CAAC,EAAE,oBAAoB,KACxB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,GAAG,YAAY,CAAC,YAAY,CAsB5F,CAAC;AAEpB,MAAM,WAAW,OAAO;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAEnB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,SAAS,sBAAsB,EAAE,CAAC;IACpD,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,UAAW,OAAO,KAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CAsQxG,CAAC"}
1
+ {"version":3,"file":"AgentService.d.ts","sourceRoot":"","sources":["../../../../src/agent-service/AgentService.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAOtC,OAAO,KAAK,YAAY,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAc,QAAQ,EAAQ,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAqB,MAAM,YAAY,CAAC;AAIpD,OAAO,EAAoD,KAAK,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AACnH,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAM3D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,CAC1B,IAAI,CAAC,EAAE,oBAAoB,KACxB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,GAAG,YAAY,CAAC,YAAY,CAsB5F,CAAC;AAEpB,MAAM,WAAW,OAAO;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;OAEG;IACH,YAAY,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAEnB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IAExC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,SAAS,sBAAsB,EAAE,CAAC;IACpD,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,KAAK,UAAW,OAAO,KAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CA0QxG,CAAC"}