@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 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-AgentService.mjs","names":[],"sources":["../../src/agent-service/agent-process.ts","../../src/agent-service/AgentService.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Tool from '@effect/ai/Tool';\nimport * as Toolkit from '@effect/ai/Toolkit';\nimport * as Cause from 'effect/Cause';\nimport * as DateTime from 'effect/DateTime';\nimport * as Duration from 'effect/Duration';\nimport * as Effect from 'effect/Effect';\nimport * as Exit from 'effect/Exit';\nimport * as Layer from 'effect/Layer';\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\nimport * as Schema from 'effect/Schema';\n\nimport { AiService, OpaqueToolkit } from '@dxos/ai';\nimport {\n AgentRequestBegin,\n AgentRequestEnd,\n AiSession,\n HarnessControl,\n SkillHooks,\n getOperationFromTool,\n makeToolExecutionService,\n makeToolResolverFromOperations,\n} from '@dxos/assistant';\nimport { Credential, Instructions, McpServer, Operation, Trace } from '@dxos/compute';\nimport { Process } from '@dxos/compute';\nimport { ProcessManager } from '@dxos/compute-runtime';\nimport * as StorageService from '@dxos/compute/StorageService';\nimport { Annotation, Database, Feed, Obj, Ref, Registry } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { DXN } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { ContentBlock } from '@dxos/types';\nimport { trim } from '@dxos/util';\n\nimport { type DelegationStrategy } from './delegation-strategy';\n\ninterface AgentProcessOptions {\n // TODO(burdon): Instructions?\n systemPrompt?: string;\n\n /** Model identifier. */\n model?: DXN.DXN;\n\n /**\n * The catalog's shared model ids are served by several providers, so resolution needs the provider\n * alongside the id; without it a local model id cannot be claimed by any resolver.\n */\n provider?: DXN.DXN;\n\n /**\n * If true, long-running tool calls are moved to the background after `backgroundThreshold`\n * and the agent is notified asynchronously when they complete.\n *\n * Currently unstable — disabled by default.\n * @default false\n */\n enableToolBackgrounding?: boolean;\n\n /**\n * When provided, the agent acts as a supervisor: after each turn it delegates outstanding work to\n * linked child processes and folds their results back into the conversation on completion. Absent\n * (the default) the process behaves as a plain conversational agent.\n */\n delegationStrategy?: DelegationStrategy;\n\n /**\n * Provider for space-level MCP server configs, called on each turn.\n */\n getMcpServers?: () => McpServer.McpServer[];\n}\n\nexport const AGENT_PROCESS_KEY = 'org.dxos.testing.process.agent';\n\n/**\n * Hosts a persistent, suspendible AiAgent that can process a number of prompts.\n * The process target is a queue DXN string.\n */\nexport const AgentProcess = (options: AgentProcessOptions) =>\n Process.make(\n {\n key: AGENT_PROCESS_KEY,\n // String member keeps queue entries persisted before the block-array widening decodable.\n input: Schema.Union(Schema.String, Schema.Array(ContentBlock.Any)),\n output: Schema.Void,\n services: [\n Database.Service,\n OpaqueToolkit.OpaqueToolkitProvider,\n Operation.Service,\n Registry.Service,\n StorageService.StorageService,\n ProcessManager.ProcessOperationInvoker.Service,\n AiService.AiService,\n // Needed in the fiber's context — `Header.byokLayer`'s per-request callback reads it.\n Credential.CredentialsService,\n ],\n rpcs: HarnessControl,\n },\n (ctx) =>\n Effect.gen(function* () {\n const feedDxn = Annotation.getDictionary(ctx.params.annotations, Process.TargetAnnotation).pipe(\n Option.getOrUndefined,\n );\n if (feedDxn == null) {\n return yield* Effect.die(new Error('Agent executable requires spawn options.target set to a queue DXN.'));\n }\n const feed = yield* Database.resolve(feedDxn, Feed.Feed).pipe(Effect.orDie);\n // Steering instructions travel as a spawn annotation (the session is feed-centric and cannot\n // reach its Chat); a broken ref degrades to an unsteered session rather than failing the process.\n const instructionsDxn = Annotation.getDictionary(ctx.params.annotations, Process.InstructionsAnnotation).pipe(\n Option.getOrUndefined,\n );\n const instructions = instructionsDxn\n ? yield* Database.resolve(instructionsDxn, Instructions.Instructions).pipe(\n Effect.orElseSucceed(() => undefined),\n )\n : undefined;\n const runtime = yield* Effect.runtime<Database.Service>();\n const session = yield* EffectEx.acquireReleaseResource(\n () => new AiSession.Session({ feed, runtime, instructions: instructions ? [instructions] : [] }),\n );\n let inputQueue: AgentEvent[] = [...(yield* AgentEventsCell.get)];\n const storageService = yield* StorageService.StorageService;\n const toolCallManager = new ToolCallManager(storageService);\n yield* toolCallManager.load();\n\n // Read time from the ambient Effect Clock so alarm scheduling and the due-check stay\n // consistent (and both honor a TestClock under tests).\n const clock = yield* Effect.clock;\n const alarmManager = new AlarmManager({\n storageService,\n setAlarm: (timeout) => ctx.setAlarm(timeout),\n now: () => clock.unsafeCurrentTimeMillis(),\n });\n yield* alarmManager.load();\n // Queued tool results were never consumed by onAlarm — reported flags from the synchronous\n // execution path are stale after reload and would cause onAlarm to drop them.\n yield* toolCallManager.reconcileWithInputQueue(inputQueue);\n\n // Optional supervisor behaviour: when a strategy is provided, the agent reconciles\n // outstanding work into linked child processes after each turn and folds their results back\n // into the conversation on completion. Absent (the default), the process behaves as a plain\n // conversational agent.\n const strategy = Option.fromNullable(options.delegationStrategy);\n let delegations: Delegation[] = [...(yield* DelegationsCell.get)];\n\n const requestModelLayer = AiService.model(\n options.model ? DXN.getName(options.model) : 'com.anthropic.model.claude-opus-4-8.default',\n {\n provider: options.provider,\n },\n );\n\n const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;\n\n // Fire end-request hooks declared by the bound skills (e.g. the planning plan-reminder).\n // Each hook runs as a child operation with `conversation` set, so it resolves the full\n // HarnessService (Tier B) and can enqueue a continuation back onto this host's queue — which\n // keeps the process alive past this turn.\n const runEndRequestHooks = Effect.gen(function* () {\n yield* SkillHooks.runHooks({\n skills: session.context.getSkills(),\n phase: 'end-request',\n invoke: (operation, input) =>\n Effect.gen(function* () {\n const fiber = yield* operationInvoker.invokeFiber(operation, input, {\n environment: { conversation: Obj.getURI(feed) },\n traceMeta: { conversation: Ref.make(feed) },\n });\n // `fiber.await` yields an Exit; surface a child failure into the Effect channel so\n // the outer `Effect.orDie` (and the hook runner's `catchAllCause`) handle it instead\n // of the failure being silently discarded.\n const exit = yield* fiber.await;\n if (Exit.isFailure(exit)) {\n yield* Effect.failCause(exit.cause);\n }\n }).pipe(Effect.asVoid, Effect.orDie),\n });\n });\n\n const maybeComplete = Effect.gen(function* () {\n if (isAgentWorkPending({ inputQueue, alarmManager, delegations, toolCallManager })) {\n return;\n }\n\n // The hook may enqueue work (e.g. a plan continuation reminder) via HarnessService Tier B,\n // which pushes onto `inputQueue`; re-check before succeeding so the turn is not dropped.\n yield* runEndRequestHooks;\n if (isAgentWorkPending({ inputQueue, alarmManager, delegations, toolCallManager })) {\n log('agent work enqueued by end-request hook, continuing');\n alarmManager.reconcile(true);\n return;\n }\n\n log('agent work complete, succeeding');\n ctx.succeed();\n });\n\n return {\n // Control plane (§4.3): handlers run on the host process's server fiber, closing over the\n // live `alarmManager`/`inputQueue` and persisting their durable effect inline.\n rpcHandlers: yield* HarnessControl.toHandlersContext({\n setAlarm: Effect.fn(function* ({ at, message }) {\n yield* alarmManager.setWakeAt(DateTime.toEpochMillis(at), message);\n alarmManager.reconcile(inputQueue.length > 0);\n }),\n enqueueMessage: Effect.fn(function* ({ content }) {\n inputQueue.push({ _tag: 'prompt', content });\n yield* AgentEventsCell.set(inputQueue);\n alarmManager.reconcile(true);\n }),\n }),\n onInput: Effect.fnUntraced(function* (prompt: string | readonly ContentBlock.Any[]) {\n log('agent onInput received', { backlog: inputQueue.length });\n const content = typeof prompt === 'string' ? [ContentBlock.Text.make({ text: prompt })] : [...prompt];\n inputQueue.push({ _tag: 'prompt', content });\n log('agent onInput persisting queue', { depth: inputQueue.length });\n yield* AgentEventsCell.set(inputQueue);\n log('agent onInput persisted', { depth: inputQueue.length });\n alarmManager.reconcile(true);\n log('agent onInput alarm scheduled');\n }),\n onAlarm: Effect.fnUntraced(\n function* () {\n log('agent onAlarm fired', { pending: inputQueue.length });\n\n // If the agent scheduled a self-wake that has come due, enqueue a wake-up prompt.\n const fired = yield* alarmManager.takeFiredAlarm();\n if (fired != null) {\n log('agent onAlarm self-wake', { firedAt: fired.firedAt });\n inputQueue.push({ _tag: 'alarm', firedAt: fired.firedAt, message: fired.message });\n yield* AgentEventsCell.set(inputQueue);\n }\n\n // Skip reported tool results at head of queue (stale after reload).\n while (inputQueue.length > 0) {\n const head = inputQueue[0];\n if (head._tag === 'tool_result' && toolCallManager.isReported(head.pid)) {\n inputQueue.shift();\n log.info('skip tool result that was reported synchronously', { pid: head.pid });\n continue;\n }\n break;\n }\n\n const item = inputQueue.shift();\n if (!item) {\n log('agent onAlarm empty queue', {});\n alarmManager.reconcile(false);\n yield* AgentEventsCell.set(inputQueue);\n yield* maybeComplete;\n return;\n }\n\n log('agent onAlarm handling', { tag: item._tag });\n\n const prompt: ContentBlock.Any[] = Match.value(item).pipe(\n Match.tag('prompt', (item) => [...item.content]),\n Match.tag('tool_result', (item) =>\n item.isError\n ? [\n ContentBlock.Text.make({\n text: toolErrorResponse(item.pid, item.result as string),\n disposition: 'synthetic',\n }),\n ]\n : [\n ContentBlock.Text.make({\n text: toolResultResponse(item.pid, item.result),\n disposition: 'synthetic',\n }),\n ],\n ),\n Match.tag('alarm', (item) => [\n ContentBlock.Text.make({ text: wakeUpPrompt(item.firedAt, item.message), disposition: 'synthetic' }),\n ]),\n Match.exhaustive,\n );\n\n log('begin request', { prompt });\n log('trace agent request begin');\n yield* Trace.write(AgentRequestBegin, {});\n yield* session\n .createRequest({\n prompt,\n // TODO(dmaretskyi): Polling currently broken, agent relies on completion notifications being delivered.\n // toolkit: AsynchronousExectionToolkit,\n // The alarm tools (set-alarm/get-current-date) now arrive as a bound blueprint whose\n // operations reach this host's AlarmManager over HarnessService Tier B.\n system: options.systemPrompt,\n mcpServers: options.getMcpServers?.(),\n })\n .pipe(\n Effect.onExit((exit) =>\n Trace.write(AgentRequestEnd, {\n status: Exit.isSuccess(exit) ? 'success' : Exit.isInterrupted(exit) ? 'interrupted' : 'error',\n error: Exit.isFailure(exit) ? Cause.pretty(exit.cause) : undefined,\n }),\n ),\n );\n log('end request');\n yield* AgentEventsCell.set(inputQueue);\n\n // Reconcile outstanding work into linked child processes (supervisor behaviour). The\n // children are linked, so their exits wake `onChildEvent` below.\n if (Option.isSome(strategy)) {\n const activeIds = new Set(delegations.map((delegation) => delegation.id));\n const pending = yield* strategy.value.reconcile(feed, activeIds);\n for (const delegation of pending) {\n const pid = yield* delegation.spawn;\n delegations.push({ pid, id: delegation.id });\n log('delegated work', { pid, id: delegation.id });\n }\n if (pending.length > 0) {\n yield* DelegationsCell.set(delegations);\n }\n }\n\n // Reconcile so a pending agent self-wake (or remaining queue work) is rescheduled.\n alarmManager.reconcile(inputQueue.length > 0);\n yield* maybeComplete;\n },\n Effect.orDie,\n Effect.provide(\n Layer.mergeAll(\n makeToolResolverFromOperations(),\n ToolExecutionService({\n toolCallManager,\n feed,\n enableBackgrounding: options.enableToolBackgrounding ?? false,\n }),\n AsynchronousExectionToolkitLayer,\n requestModelLayer,\n ).pipe(Layer.orDie),\n ),\n ),\n onChildEvent: Effect.fnUntraced(function* (event) {\n log('childEvent', { event });\n if (event._tag === 'exited') {\n // A delegated sub-agent finished: read its result and hand it to the strategy (which\n // updates the work item and notifies the user). Unlike tool results, this does not\n // re-enter the turn — the supervisor folds it in out of band.\n const delegation = delegations.find((delegation) => delegation.pid === event.pid);\n if (delegation) {\n delegations = delegations.filter((other) => other.pid !== event.pid);\n yield* DelegationsCell.set(delegations);\n const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;\n const fiber = yield* operationInvoker.attachFiber(event.pid).pipe(Effect.orDie);\n const exit = yield* fiber.await;\n if (Option.isSome(strategy)) {\n yield* strategy.value.onComplete(feed, delegation.id, exit);\n }\n log('delegated work completed', { pid: event.pid, id: delegation.id, success: Exit.isSuccess(exit) });\n yield* maybeComplete;\n } else if (toolCallManager.isToolCall(event.pid)) {\n const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;\n const attachExit = yield* operationInvoker.attachFiber(event.pid).pipe(Effect.exit);\n if (Exit.isFailure(attachExit)) {\n // Completed tool children are not rehydrated on reload; the result is in inputQueue or was\n // delivered synchronously before the interrupted turn.\n if (\n toolCallManager.isToolCall(event.pid) ||\n inputQueue.some((item) => item._tag === 'tool_result' && item.pid === event.pid) ||\n toolCallManager.isReported(event.pid)\n ) {\n log.verbose('childEvent skipped (process gone, result already handled)', { pid: event.pid });\n return;\n }\n return yield* Effect.failCause(attachExit.cause).pipe(Effect.orDie);\n }\n const fiber = attachExit.value;\n const result = yield* fiber.await.pipe(Effect.orDie).pipe(\n Effect.map(\n Exit.match({\n onSuccess: (value): AgentEvent => ({\n _tag: 'tool_result',\n pid: event.pid,\n result: value,\n isError: false,\n }),\n onFailure: (cause): AgentEvent => ({\n _tag: 'tool_result',\n pid: event.pid,\n result: Cause.pretty(cause),\n isError: true,\n }),\n }),\n ),\n );\n inputQueue.push(result);\n log('agent onChildEvent persisted tool result', { depth: inputQueue.length, childPid: event.pid });\n yield* AgentEventsCell.set(inputQueue);\n alarmManager.reconcile(true);\n log('agent onChildEvent alarm scheduled', { depth: inputQueue.length });\n } else {\n log.verbose('childEvent ignored non-tool call and not a delegation', { pid: event.pid });\n }\n }\n }),\n };\n }),\n );\n\ninterface ToolExecutionServiceOptions {\n /**\n * If true, tool calls that exceed `backgroundThreshold` are detached and the agent is told\n * the call is running in the background. If false, the executor always blocks on the call.\n */\n enableBackgrounding: boolean;\n\n /**\n * Threshold after which the tool execution is placed in the background.\n * Ignored when `enableBackgrounding` is false.\n */\n // TODO(dmaretskyi): Tool annotation to never run in background.\n backgroundThreshold?: Duration.Duration;\n\n toolCallManager: ToolCallManager;\n\n feed: Feed.Feed;\n}\n\nconst AgentEvent = Schema.Union(\n Schema.TaggedStruct('prompt', {\n content: Schema.Array(ContentBlock.Any),\n }),\n Schema.TaggedStruct('tool_result', {\n pid: Process.ID,\n result: Schema.Unknown,\n isError: Schema.Boolean,\n }),\n Schema.TaggedStruct('alarm', {\n firedAt: Schema.Number,\n // Optional reminder carried from the self-wake; surfaced to the agent when the alarm fires.\n message: Schema.NullOr(Schema.String),\n }),\n);\ntype AgentEvent = Schema.Schema.Type<typeof AgentEvent>;\n\nconst AgentEventsCell = StorageService.cell(\n Schema.parseJson(Schema.Array(AgentEvent).pipe(Schema.mutable)),\n 'inputQueue',\n).pipe(StorageService.withDefault(() => []));\n\n/**\n * Tracks delegated sub-agent child processes (pid -> correlation id) so that, after a hibernation,\n * a delegated child's exit can be matched back to the work it was fulfilling.\n */\nconst Delegation = Schema.Struct({ pid: Process.ID, id: Schema.String }).pipe(Schema.mutable);\ntype Delegation = Schema.Schema.Type<typeof Delegation>;\n\nconst DelegationsCell = StorageService.cell(\n Schema.parseJson(Schema.Array(Delegation).pipe(Schema.mutable)),\n 'delegations',\n).pipe(StorageService.withDefault(() => []));\n\nconst ToolCallState = Schema.Struct({\n activeCalls: Schema.Array(\n Schema.Struct({\n pid: Process.ID,\n // Whether the result was reported to the agent.\n reported: Schema.Boolean,\n }).pipe(Schema.mutable),\n ).pipe(Schema.mutable),\n});\ninterface ToolCallState extends Schema.Schema.Type<typeof ToolCallState> {}\n\n// Id's of processes who's results were already submitted to the agent.\nconst ToolCallStateCell = StorageService.cell(\n Schema.parseJson(ToolCallState.pipe(Schema.mutable)),\n 'toolCallState',\n).pipe(StorageService.withDefault(() => ({ activeCalls: [] })));\n\nclass ToolCallManager {\n #storageService: StorageService.Service;\n #state: ToolCallState = { activeCalls: [] };\n\n constructor(storageService: StorageService.Service) {\n this.#storageService = storageService;\n }\n\n load() {\n return Effect.gen(this, function* () {\n this.#state = yield* ToolCallStateCell.get;\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n beginCall(pid: Process.ID) {\n return Effect.gen(this, function* () {\n this.#state.activeCalls.push({ pid, reported: false });\n yield* ToolCallStateCell.set(this.#state);\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n markAsReported(pid: Process.ID) {\n return Effect.gen(this, function* () {\n const call = this.#state.activeCalls.find((call) => call.pid === pid);\n if (!call) {\n return;\n }\n call.reported = true;\n yield* ToolCallStateCell.set(this.#state);\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n isToolCall(pid: Process.ID): boolean {\n return this.#state.activeCalls.some((call) => call.pid === pid);\n }\n\n isReported(pid: Process.ID) {\n return this.#state.activeCalls.some((call) => call.pid === pid && call.reported);\n }\n\n /** True while a tool-call result has not yet been delivered back to the agent turn. */\n hasPendingToolResults(): boolean {\n return this.#state.activeCalls.some((call) => !call.reported);\n }\n\n /**\n * Clears reported flags for tool calls that still have a pending queue entry.\n * After reload the in-flight createRequest is gone, so those results must be redelivered via onAlarm.\n */\n reconcileWithInputQueue(queue: readonly AgentEvent[]) {\n return Effect.gen(this, function* () {\n let changed = false;\n for (const item of queue) {\n if (item._tag !== 'tool_result') {\n continue;\n }\n const call = this.#state.activeCalls.find((entry) => entry.pid === item.pid);\n if (call?.reported) {\n call.reported = false;\n changed = true;\n log('reconcile queued tool result', { pid: item.pid });\n }\n }\n if (changed) {\n yield* ToolCallStateCell.set(this.#state);\n }\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n}\n\nexport type AgentIdleSnapshot = {\n inputQueue: readonly AgentEvent[];\n alarmManager: AlarmManager;\n delegations: readonly Delegation[];\n // Only the pending-results check is consulted, so the predicate stays decoupled from the rest of\n // the ToolCallManager surface (and is trivially stubbable in tests).\n toolCallManager: Pick<ToolCallManager, 'hasPendingToolResults'>;\n};\n\n/** True while the agent still has queued work, a self-wake, subprocesses, or undelivered tool results. */\nexport const isAgentWorkPending = ({\n inputQueue,\n alarmManager,\n delegations,\n toolCallManager,\n}: AgentIdleSnapshot): boolean =>\n inputQueue.length > 0 ||\n alarmManager.wakeAt != null ||\n delegations.length > 0 ||\n toolCallManager.hasPendingToolResults();\n\n//\n// Alarms.\n//\n\n/**\n * Persisted next agent-scheduled self-wake: the UNIX timestamp (ms) and an optional reminder\n * message delivered when it fires, or `null` when no self-wake is set.\n */\nconst AgentAlarmCell = StorageService.cell(\n Schema.parseJson(Schema.NullOr(Schema.Struct({ wakeAt: Schema.Number, message: Schema.NullOr(Schema.String) }))),\n 'agentAlarm',\n).pipe(StorageService.withDefault(() => null));\n\n/**\n * Computes the timeout to pass to `ctx.setAlarm`, reconciling pending queue work with the agent's\n * self-wake alarm. Returns `null` when no alarm should be scheduled (process can go idle).\n */\nexport const computeAlarmDelay = ({\n hasPendingWork,\n wakeAt,\n now,\n}: {\n hasPendingWork: boolean;\n wakeAt: number | null;\n now: number;\n}): number | null => {\n if (hasPendingWork) {\n return 0;\n }\n if (wakeAt != null) {\n return Math.max(0, wakeAt - now);\n }\n return null;\n};\n\ninterface AlarmManagerOptions {\n storageService: StorageService.Service;\n setAlarm: (timeout?: number) => void;\n\n /**\n * Source of the current time. Injectable for deterministic tests.\n * @default () => Date.now()\n */\n now?: () => number;\n}\n\n/**\n * Tracks the next agent-scheduled self-wake and keeps it in sync with the process alarm\n * (`ctx.setAlarm`). The agent sets alarms via the alarm blueprint, which dispatches to this manager\n * through the `HarnessControl` RPC surface; the process reconciles the underlying single-shot alarm\n * timer to fire at the earliest of pending work or the self-wake.\n */\nexport class AlarmManager {\n readonly #storageService: StorageService.Service;\n readonly #setAlarm: (timeout?: number) => void;\n readonly #now: () => number;\n #wakeAt: number | null = null;\n #message: string | null = null;\n\n constructor({ storageService, setAlarm, now = () => Date.now() }: AlarmManagerOptions) {\n this.#storageService = storageService;\n this.#setAlarm = setAlarm;\n this.#now = now;\n }\n\n /** Currently scheduled self-wake timestamp (ms), or `null` when none is set. */\n get wakeAt(): number | null {\n return this.#wakeAt;\n }\n\n /** Reminder message delivered when the current self-wake fires, or `null` when none is set. */\n get message(): string | null {\n return this.#message;\n }\n\n now(): number {\n return this.#now();\n }\n\n /** Restores the persisted alarm state. */\n load(): Effect.Effect<void> {\n return Effect.gen(this, function* () {\n const persisted = yield* AgentAlarmCell.get;\n this.#wakeAt = persisted?.wakeAt ?? null;\n this.#message = persisted?.message ?? null;\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n /** Records a new self-wake target (with an optional reminder message) and persists it. */\n setWakeAt(wakeAt: number, message: string | null = null): Effect.Effect<void> {\n return Effect.gen(this, function* () {\n this.#wakeAt = wakeAt;\n this.#message = message;\n yield* AgentAlarmCell.set({ wakeAt, message });\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n /**\n * Clears the self-wake alarm if it is due, returning the timestamp it was scheduled for and the\n * reminder message it carried (or `null` if no alarm was due).\n */\n takeFiredAlarm(): Effect.Effect<{ firedAt: number; message: string | null } | null> {\n return Effect.gen(this, function* () {\n if (this.#wakeAt == null || this.#now() < this.#wakeAt) {\n return null;\n }\n const firedAt = this.#wakeAt;\n const message = this.#message;\n this.#wakeAt = null;\n this.#message = null;\n yield* AgentAlarmCell.set(null);\n return { firedAt, message };\n }).pipe(Effect.provideService(StorageService.StorageService, this.#storageService));\n }\n\n /**\n * Reconciles the process alarm timer with pending work and the tracked self-wake, scheduling the\n * earliest of the two. Does nothing when there is neither pending work nor a self-wake.\n */\n reconcile(hasPendingWork: boolean): void {\n const delay = computeAlarmDelay({ hasPendingWork, wakeAt: this.#wakeAt, now: this.#now() });\n if (delay != null) {\n this.#setAlarm(delay);\n }\n }\n}\n\n/**\n * Prompt delivered to the agent when a self-scheduled alarm fires. When the alarm carried a\n * reminder message it is surfaced verbatim, otherwise a generic continuation prompt is used.\n */\nconst wakeUpPrompt = (firedAt: number, message: string | null): string =>\n message != null\n ? trim`\n Your scheduled alarm fired (it was set for ${new Date(firedAt).toISOString()}).\n ${message}\n `\n : trim`\n Your scheduled alarm fired (it was set for ${new Date(firedAt).toISOString()}).\n Continue with whatever you intended to do when you scheduled this wake-up.\n `;\n\nconst ToolExecutionService = ({\n enableBackgrounding,\n backgroundThreshold = Duration.seconds(1),\n toolCallManager,\n feed,\n}: ToolExecutionServiceOptions) =>\n Layer.unwrapEffect(\n Effect.gen(function* () {\n const operationInvoker = yield* ProcessManager.ProcessOperationInvoker.Service;\n return makeToolExecutionService({\n invoke: (tool, input) =>\n Effect.gen(function* () {\n const operationDef = getOperationFromTool(tool).pipe(Option.getOrThrow);\n log('invoking operation', { operationDef, input });\n const fiber = yield* operationInvoker.invokeFiber(operationDef, input, {\n environment: {\n conversation: Obj.getURI(feed),\n },\n traceMeta: {\n conversation: Ref.make(feed),\n },\n });\n yield* toolCallManager.beginCall(fiber.pid);\n log('invoked operation', { operationDef, input, fiber });\n\n const awaitWithReport = fiber.await.pipe(Effect.tap(() => toolCallManager.markAsReported(fiber.pid)));\n const result = enableBackgrounding\n ? yield* awaitWithReport.pipe(\n Effect.timeout(backgroundThreshold),\n Effect.catchTag('TimeoutException', () =>\n Effect.succeed(Exit.succeed(toolIsRunningInBackgroundResponse(fiber.pid))),\n ),\n )\n : yield* awaitWithReport;\n log('result', { result });\n return yield* result;\n }),\n });\n }),\n );\n\nclass AsynchronousExectionToolkit extends Toolkit.make(\n Tool.make('poll-tools', {\n description: trim`\n Poll tool calls running in the background.\n Set wait to true to wait for the tool call to complete before returning.\n Only set wait to true if you dont have other tasks to perform in parallel.\n Set an appropriate timeout to avoid waiting forever.\n You will also be notified about the job completion separatelly, so you do not always need to inspect the job if you dont need the result right now.\n `,\n parameters: {\n ids: Schema.Array(Schema.String).annotations({\n description: 'The IDs of the jobs to inspect.',\n }),\n wait: Schema.optional(Schema.Boolean).annotations({\n description: 'Whether to wait for the tool call to complete before returning.',\n default: false,\n }),\n timeout: Schema.optional(Schema.Number).annotations({\n description:\n 'Maximum time to wait for the job to complete. If the job does not complete within the timeout, the current state is returned.',\n default: 10_000,\n }),\n },\n }),\n) {}\n\n// TODO(dmaretskyi): Currently broken: polling a completed process returns interruped error.\nconst AsynchronousExectionToolkitLayer = AsynchronousExectionToolkit.toLayer(\n Effect.gen(function* () {\n const invoker = yield* ProcessManager.ProcessOperationInvoker.Service;\n return {\n 'poll-tools': ({ ids, wait, timeout = 10_000 }) =>\n Effect.gen(function* () {\n return yield* Effect.forEach(ids, (pid) =>\n invoker.attachFiber<unknown>(Process.ID.make(pid)).pipe(\n Effect.flatMap((_) => _.await),\n Effect.timeout(Duration.millis(timeout)),\n Effect.flatMap(\n Exit.match({\n onSuccess: (value) => Effect.succeed(toolResultResponse(pid, value)),\n onFailure: (cause) => Effect.succeed(toolErrorResponse(pid, Cause.pretty(cause))),\n }),\n ),\n Effect.catchTag('ProcessNotFoundError', () => Effect.succeed(`Process not found: ${pid}`)),\n Effect.catchTag('TimeoutException', () => Effect.succeed(`Process still running: ${pid}`)),\n ),\n );\n }),\n };\n }),\n);\n\n/**\n * Instructs model that the tool is running in the background.\n */\nconst toolIsRunningInBackgroundResponse = (pid: Process.ID) =>\n `Tool is running in the background (id=${pid}); wait for the completion notification to get the result.`;\n// `Tool is running in the background (id=${pid}); use ${AsynchronousExectionToolkit.tools['poll-tools'].name} to get the result.`;\n\nconst toolResultResponse = (pid: string, value: unknown) => `<result pid=${pid}>${JSON.stringify(value)}</result>`;\n\nconst toolErrorResponse = (pid: string, cause: string) => `<error pid=${pid}>${cause}</error>`;\n","//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Cause from 'effect/Cause';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Option from 'effect/Option';\n\nimport { AiContext } from '@dxos/assistant';\nimport { McpServer, Process, Skill } from '@dxos/compute';\nimport { ProcessManager } from '@dxos/compute-runtime';\nimport {\n AgentService,\n type GetSessionOptions,\n type Service,\n type Session,\n getSession,\n} from '@dxos/compute/AgentService';\nimport { Annotation, Database, Feed, Obj, Ref, Registry } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { DXN, EID } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport type { ContentBlock } from '@dxos/types';\n\nimport { AGENT_PROCESS_KEY, AgentProcess } from './agent-process';\nimport { type DelegationStrategy } from './delegation-strategy';\n\n/** The RPC control surface declared by {@link AgentProcess}, recovered from the executable type. */\ntype AgentRpcs = ReturnType<typeof AgentProcess> extends Process.Process<any, any, any, infer Rpcs> ? Rpcs : never;\n\n/** Live handle to a spawned {@link AgentProcess}, carrying its `HarnessControl` RPC surface. */\ntype AgentHandle = ProcessManager.Handle<string | ContentBlock.Any[], void, AgentRpcs>;\n\nconst isTerminalProcess = (state: Process.State): boolean =>\n state === Process.State.SUCCEEDED || state === Process.State.FAILED || state === Process.State.TERMINATED;\n\n// TODO(burdon): Agent identity?\nexport interface CreateSessionOptions {\n readonly skills?: Skill.Skill[];\n readonly context?: Ref.Ref<Obj.Unknown>[];\n readonly model?: DXN.DXN;\n readonly provider?: DXN.DXN;\n readonly systemPrompt?: string;\n}\n\nexport const createSession: (\n opts?: CreateSessionOptions,\n) => Effect.Effect<Session, Skill.NotFoundError, Database.Service | Registry.Service | AgentService> = Effect.fn(\n 'createSession',\n)(function* (opts) {\n const skills = yield* Effect.forEach(opts?.skills ?? [], (skill) =>\n Skill.upsert(Skill.getKey(skill)).pipe(Effect.map(Ref.make)),\n );\n\n const feed = yield* Database.add(Feed.make());\n const runtime = yield* Effect.runtime<Database.Service>();\n const binder = yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({ feed, runtime }));\n\n yield* Effect.promise(() =>\n binder.bind({\n skills,\n objects: opts?.context ?? [],\n }),\n );\n\n return yield* getSession(feed, { model: opts?.model, provider: opts?.provider });\n}, Effect.scoped);\n\nexport interface AgentServiceOptions {\n systemPrompt?: string;\n\n /**\n * Default model used by sessions that don't specify one explicitly.\n */\n model?: DXN.DXN;\n\n /**\n * Default provider used to resolve the model for sessions that don't specify one explicitly.\n */\n provider?: DXN.DXN;\n\n /**\n * If true, long-running tool calls are moved to the background and the agent is notified\n * asynchronously when they complete. Currently unstable — disabled by default.\n *\n * @default false\n */\n enableToolBackgrounding?: boolean;\n\n /**\n * When provided, sessions act as supervisors: the agent delegates outstanding work to sub-agent\n * child processes and folds their results back into the conversation. Absent — a plain agent.\n */\n delegationStrategy?: DelegationStrategy;\n\n /**\n * Provider for space-level MCP server configs.\n */\n getMcpServers?: () => McpServer.McpServer[];\n}\n\nexport const layer = (opts?: AgentServiceOptions): Layer.Layer<AgentService, never, ProcessManager.Service> =>\n Layer.effect(\n AgentService,\n Effect.gen(function* () {\n const processManager = yield* ProcessManager.Service;\n // The agent's model and steering instructions are bound to its process at spawn time, so the\n // cache tracks what each session was created with. Requesting a different model or a repointed\n // instructions ref for the same feed tears down the old process and spawns a fresh one (see below).\n const sessionCache = new Map<\n string,\n {\n model: DXN.DXN | undefined;\n provider: DXN.DXN | undefined;\n instructions: string | undefined;\n handle: AgentHandle;\n session: Session;\n }\n >();\n\n const makeExecutable = (model?: DXN.DXN, provider?: DXN.DXN) =>\n AgentProcess({\n systemPrompt: opts?.systemPrompt,\n model: model ?? opts?.model,\n provider: provider ?? opts?.provider,\n getMcpServers: opts?.getMcpServers,\n enableToolBackgrounding: opts?.enableToolBackgrounding,\n delegationStrategy: opts?.delegationStrategy,\n });\n\n const hydrateAgents = Effect.fnUntraced(function* () {\n // Handles cached before shutdown are suspended and no longer registered with the manager.\n sessionCache.clear();\n\n const executable = makeExecutable();\n const agents = yield* processManager.list({ key: AGENT_PROCESS_KEY });\n log('agent hydrate', { count: agents.length });\n for (const agent of agents) {\n yield* agent\n .hydrate(executable)\n .pipe(\n Effect.catchAllCause((cause) =>\n Effect.sync(() => log.warn('agent hydrate skipped', { pid: agent.pid, cause: Cause.pretty(cause) })),\n ),\n );\n }\n });\n\n const service: Service = {\n getSession: (feed: Feed.Feed, options?: GetSessionOptions) =>\n Effect.gen(function* () {\n const model = options?.model ?? opts?.model;\n const provider = options?.provider ?? opts?.provider;\n const instructions = options?.instructions?.uri;\n const cached = sessionCache.get(feed.id);\n if (cached) {\n if (\n cached.model === model &&\n cached.provider === provider &&\n cached.instructions === instructions &&\n !isTerminalProcess(cached.handle.status.state)\n ) {\n return cached.session;\n }\n\n if (!isTerminalProcess(cached.handle.status.state)) {\n // Model, provider, or steering instructions changed (e.g. the user toggled\n // online/offline, or the chat's instructions ref was repointed): terminate the\n // existing process so the conversation continues on a fresh process bound to the new\n // configuration. Conversation history is preserved via the feed, which the new\n // process replays.\n yield* cached.handle.terminate();\n }\n sessionCache.delete(feed.id);\n }\n\n const target = Obj.getURI(feed);\n const parsedEchoUri = EID.tryParse(target);\n const spaceId = parsedEchoUri ? EID.getSpaceId(parsedEchoUri) : undefined;\n const executable = makeExecutable(model, provider);\n\n // Reuse a still-running process for this feed only when there was no cached session\n // (e.g. after the UI remounted). After a model change we always spawn a fresh process,\n // since the process key does not encode the model.\n const processes = yield* processManager.list({ target, key: executable.key });\n let activeProcess = processes.find((process) => !isTerminalProcess(process.status.state));\n\n // Spawn annotations are immutable, so a running process found via the remount path may\n // carry stale instructions; terminate it and respawn with the requested ref.\n if (activeProcess) {\n const processInstructions = Option.getOrUndefined(\n Annotation.getDictionary(activeProcess.params.annotations, Process.InstructionsAnnotation),\n );\n if (processInstructions !== instructions) {\n yield* activeProcess.terminate();\n activeProcess = undefined;\n }\n }\n\n let handle: AgentHandle;\n if (activeProcess) {\n yield* activeProcess.hydrate(executable);\n handle = activeProcess;\n } else {\n handle = yield* processManager.spawn(executable, {\n name: 'Agent',\n target,\n // Stamp the host marker so the harness control surface is discoverable by annotation\n // lookup (set once at spawn, immutable — the identity plane).\n annotations: Annotation.buildDictionary((dictionary) => {\n Annotation.setDictionary(dictionary, Process.HarnessHostAnnotation, true);\n if (options?.instructions) {\n Annotation.setDictionary(dictionary, Process.InstructionsAnnotation, options.instructions.uri);\n }\n }),\n environment: {\n ...(spaceId !== undefined ? { space: spaceId } : {}),\n conversation: target,\n },\n traceMeta: {\n conversation: Ref.make(feed),\n },\n });\n }\n\n const releaseSession = () => {\n sessionCache.delete(feed.id);\n };\n const session = makeSession(handle, feed, releaseSession);\n sessionCache.set(feed.id, { model, provider, instructions, handle, session });\n return session;\n }),\n hydrate: hydrateAgents,\n };\n\n return service;\n }),\n );\n\nconst makeSession = (process: AgentHandle, feed: Feed.Feed, releaseSession: () => void): Session => ({\n feed,\n getContext: () =>\n Effect.gen(function* () {\n const runtime = yield* Effect.runtime<Database.Service>();\n const binder = yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({ feed, runtime }));\n return binder.getObjects().map((object) => Ref.make(object));\n }).pipe(Effect.scoped),\n addContext: (context: Ref.Ref<Obj.Unknown>[]) =>\n Effect.gen(function* () {\n const runtime = yield* Effect.runtime<Database.Service>();\n const binder = yield* EffectEx.acquireReleaseResource(() => new AiContext.Binder({ feed, runtime }));\n yield* Effect.promise(() =>\n binder.bind({\n skills: [],\n objects: context,\n }),\n );\n }).pipe(Effect.scoped),\n submitPrompt: (prompt: string | ContentBlock.Any[]) => process.submitInput(prompt),\n // Settle when the turn's reply is complete; do NOT block on background sub-agents\n // (a supervisor delegates work that runs after the turn and reports back out of band).\n waitForCompletion: () => process.runUntilSettled(),\n terminate: () => process.terminate().pipe(Effect.tap(() => Effect.sync(releaseSession))),\n subscribeEphemeral: () => process.subscribeEphemeral(),\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { i as __exportAll, n as layer$1 } from "./chunk-AgentService.mjs";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Layer from "effect/Layer";
|
|
4
|
+
import { CompleteBlock, Harness, PartialBlock } from "@dxos/assistant";
|
|
5
|
+
import { AgentService, Credential, Instructions, Operation, OperationHandlerSet, Process, ServiceNotAvailableError, ServiceResolver, Skill, Trace, Trigger } from "@dxos/compute";
|
|
6
|
+
import { FeedTraceSink, ProcessManager, ProcessMonitor, RemoteProcessManager, RemoteTraceMonitor, TriggerDispatcher, TriggerStateStore, configuredCredentialsLayer } from "@dxos/compute-runtime";
|
|
7
|
+
import { Database, Feed, Filter, Obj, Query, Registry, Tag, Type } from "@dxos/echo";
|
|
8
|
+
import { DXN } from "@dxos/keys";
|
|
9
|
+
import { log } from "@dxos/log";
|
|
10
|
+
import * as Match from "effect/Match";
|
|
11
|
+
import { AiService, ConsolePrinter, OpaqueToolkit, Provider } from "@dxos/ai";
|
|
12
|
+
import { Message, Organization } from "@dxos/types";
|
|
13
|
+
import { TestAiService, runMemoizedTests } from "@dxos/ai/testing";
|
|
14
|
+
import { Registry as Registry$1 } from "@effect-atom/atom";
|
|
15
|
+
import * as KeyValueStore from "@effect/platform/KeyValueStore";
|
|
16
|
+
import * as Array from "effect/Array";
|
|
17
|
+
import * as Context from "effect/Context";
|
|
18
|
+
import { TestDatabaseLayer } from "@dxos/compute-runtime/testing";
|
|
19
|
+
import { registryLayer } from "@dxos/echo-client";
|
|
20
|
+
import * as Stream from "effect/Stream";
|
|
21
|
+
import { BaseError } from "@dxos/errors";
|
|
22
|
+
import * as Deferred from "effect/Deferred";
|
|
23
|
+
import * as Queue from "effect/Queue";
|
|
24
|
+
//#region src/testing/trace-pretty-print.ts
|
|
25
|
+
/**
|
|
26
|
+
* Pretty-prints assistant trace messages to stdout (CompleteBlock, process spawn/exit).
|
|
27
|
+
*/
|
|
28
|
+
var prettyPrintTraceMessage = (message) => {
|
|
29
|
+
for (const event of message.events) if (Trace.isOfType(CompleteBlock, event)) {
|
|
30
|
+
const tag = message.meta.processName ?? `${message.meta.pid ?? "unknown"}`;
|
|
31
|
+
console.log(`[${tag}] ${event.data.role.toUpperCase()}`);
|
|
32
|
+
new ConsolePrinter({ tag }).printContentBlock(event.data.block);
|
|
33
|
+
} else if (Trace.isOfType(Process.SpawnedEvent, event)) console.log(`[${message.meta.pid}] Process spawned: ${message.meta.processName}`);
|
|
34
|
+
else if (Trace.isOfType(Process.ExitedEvent, event)) console.log(`[${message.meta.pid}] Process exited: ${event.data.outcome}`);
|
|
35
|
+
};
|
|
36
|
+
/** {@link Trace.TraceSink} layer that mirrors {@link AssistantTestLayer}'s `tracing: 'pretty'` mode. */
|
|
37
|
+
var traceSinkPrettyLayer = () => Layer.succeed(Trace.TraceSink, { write: prettyPrintTraceMessage });
|
|
38
|
+
/**
|
|
39
|
+
* Subscribes to the space trace feed and pretty-prints newly appended messages.
|
|
40
|
+
* Returns an unsubscribe function. Requires ambient {@link Database.Service}.
|
|
41
|
+
*/
|
|
42
|
+
var traceFeedPrettyPrintSubscription = Effect.gen(function* () {
|
|
43
|
+
const feed = yield* FeedTraceSink.getOrCreateTraceFeed();
|
|
44
|
+
const queryResult = yield* Database.query(Query.select(Filter.type(Trace.Message)).from(feed));
|
|
45
|
+
const seen = new Set(queryResult.runSync().map((message) => message.id));
|
|
46
|
+
return queryResult.subscribe((result) => {
|
|
47
|
+
for (const message of result.results) {
|
|
48
|
+
if (seen.has(message.id)) continue;
|
|
49
|
+
seen.add(message.id);
|
|
50
|
+
prettyPrintTraceMessage(message);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/testing/assistant-test-layer.ts
|
|
56
|
+
var AssistantTestLayer = (options = {}) => {
|
|
57
|
+
const resolvedModel = options.model ?? (options.aiServicePreset === "ollama" ? DXN.make("com.openai.model.gpt-oss-20b.default") : DXN.make("com.anthropic.model.claude-opus-4-8.default"));
|
|
58
|
+
const resolvedProvider = options.provider ?? (options.aiServicePreset === "ollama" ? Provider.ollama.id : Provider.edge.id);
|
|
59
|
+
const agentOptions = { ...options.agent };
|
|
60
|
+
agentOptions.model ??= resolvedModel;
|
|
61
|
+
agentOptions.provider ??= resolvedProvider;
|
|
62
|
+
const processManagerHolder = {};
|
|
63
|
+
const agentServiceHolder = {};
|
|
64
|
+
return Layer.empty.pipe(Layer.provideMerge(captureAgentService(agentServiceHolder)), Layer.provideMerge(ProcessManager.ProcessOperationInvoker.layer), Layer.provideMerge(ProcessMonitor.layer), Layer.provideMerge(RemoteProcessManager.layerNoop), Layer.provideMerge(RemoteTraceMonitor.layerNoop), Layer.provideMerge(layer$1(agentOptions)), Layer.provideMerge(Trace.testTraceService({ meta: { processName: "test" } })), Layer.provideMerge(captureProcessManager(processManagerHolder)), Layer.provideMerge(ProcessManager.layer({ idGenerator: ProcessManager.SequentialIdGenerator })), Layer.provideMerge(AssistantTestServiceResolverLayer(options, processManagerHolder, agentServiceHolder)), Layer.provideMerge(AiService.model(DXN.getName(resolvedModel), { provider: resolvedProvider })), Layer.provideMerge(AssistantTestTracingLayer(options.tracing ?? "noop")), Layer.provideMerge(options.aiService ?? TestAiService({
|
|
65
|
+
preset: options.aiServicePreset,
|
|
66
|
+
disableMemoization: options.disableLlmMemoization,
|
|
67
|
+
dynamicValuePatterns: options.dynamicValuePatterns
|
|
68
|
+
})), Layer.provideMerge(AssistantTestBaseLayer(options)), Layer.orDie);
|
|
69
|
+
};
|
|
70
|
+
/** Fills the {@link AgentServiceHolder}, letting the resolver serve operations that relay into agent sessions. */
|
|
71
|
+
var captureAgentService = (holder) => Layer.effectDiscard(Effect.gen(function* () {
|
|
72
|
+
holder.current = yield* AgentService.AgentService;
|
|
73
|
+
}));
|
|
74
|
+
/** Fills the {@link ProcessManagerHolder} once the manager is available, breaking the build cycle. */
|
|
75
|
+
var captureProcessManager = (holder) => Layer.effectDiscard(Effect.gen(function* () {
|
|
76
|
+
holder.current = yield* ProcessManager.Service;
|
|
77
|
+
}));
|
|
78
|
+
/**
|
|
79
|
+
* Service resolver for testing.
|
|
80
|
+
*/
|
|
81
|
+
var AssistantTestServiceResolverLayer = ({ extraServices = Layer.empty }, processManagerHolder, agentServiceHolder = {}) => Layer.scoped(ServiceResolver.ServiceResolver, Effect.gen(function* () {
|
|
82
|
+
const services = yield* Effect.context().pipe(Effect.map(Context.pick(Database.Service)), Effect.map(Layer.succeedContext));
|
|
83
|
+
const extraServicesRt = yield* Layer.toRuntime(extraServices);
|
|
84
|
+
return ServiceResolver.compose(ServiceResolver.succeed(Harness.HarnessService, (context) => Effect.gen(function* () {
|
|
85
|
+
if (!context.conversation) return yield* Effect.fail(new ServiceNotAvailableError(Harness.HarnessService.key));
|
|
86
|
+
const processManager = processManagerHolder.current;
|
|
87
|
+
if (!processManager) return yield* Effect.fail(new ServiceNotAvailableError(ProcessManager.Service.key));
|
|
88
|
+
const runtime = yield* Effect.runtime();
|
|
89
|
+
return yield* Harness.make({
|
|
90
|
+
conversation: context.conversation,
|
|
91
|
+
processManager,
|
|
92
|
+
runtime
|
|
93
|
+
});
|
|
94
|
+
}).pipe(Effect.provide(services))), ServiceResolver.succeed(AgentService.AgentService, () => Effect.gen(function* () {
|
|
95
|
+
const agentService = agentServiceHolder.current;
|
|
96
|
+
if (!agentService) return yield* Effect.fail(new ServiceNotAvailableError(AgentService.AgentService.key));
|
|
97
|
+
return agentService;
|
|
98
|
+
})), yield* ServiceResolver.fromRequirements(Database.Service, OpaqueToolkit.OpaqueToolkitProvider, AiService.AiService, Registry.Service, Credential.CredentialsService), ServiceResolver.fromContext(extraServicesRt.context));
|
|
99
|
+
}));
|
|
100
|
+
/**
|
|
101
|
+
* Only storage + registry.
|
|
102
|
+
*/
|
|
103
|
+
var AssistantTestBaseLayer = ({ operationHandlers = [], toolkits = [], types = [], credentials = [], skills = [] }) => {
|
|
104
|
+
const toolkit = OpaqueToolkit.merge(...toolkits);
|
|
105
|
+
const operationHandlersSet = Array.isArray(operationHandlers) ? OperationHandlerSet.merge(...operationHandlers) : operationHandlers;
|
|
106
|
+
types.push(Skill.Skill, Instructions.Instructions, Operation.PersistentOperation, Feed.Feed, Trigger.Trigger, Tag.Tag);
|
|
107
|
+
types = Array.dedupeWith(types, (a, b) => Type.getTypename(a) === Type.getTypename(b));
|
|
108
|
+
return Layer.empty.pipe(Layer.provideMerge(TestDatabaseLayer({
|
|
109
|
+
spaceKey: "fixed",
|
|
110
|
+
types
|
|
111
|
+
})), Layer.provideMerge(configuredCredentialsLayer(credentials)), Layer.provideMerge(Layer.effect(Registry.Service, Effect.gen(function* () {
|
|
112
|
+
const handlerSet = yield* OperationHandlerSet.OperationHandlerProvider;
|
|
113
|
+
const registry = yield* Registry.Service;
|
|
114
|
+
const handlers = yield* handlerSet.handlers;
|
|
115
|
+
registry.add(handlers.map(Operation.serialize));
|
|
116
|
+
return registry;
|
|
117
|
+
}))), Layer.provideMerge(registryLayer({ initial: skills })), Layer.provideMerge(OpaqueToolkit.providerLayer(toolkit)), Layer.provideMerge(OperationHandlerSet.provide(operationHandlersSet)), Layer.provideMerge(KeyValueStore.layerMemory), Layer.provideMerge(Registry$1.layer), Layer.orDie);
|
|
118
|
+
};
|
|
119
|
+
var AssistantTestTracingLayer = (mode) => Match.value(mode).pipe(Match.when("noop", () => Layer.mergeAll(Trace.layerNoop, FeedTraceSink.layerNoop)), Match.when("console", () => Layer.mergeAll(Trace.layerConsole, FeedTraceSink.layerNoop)), Match.when("pretty", () => Layer.mergeAll(traceSinkPrettyLayer(), FeedTraceSink.layerNoop)), Match.when("feed", () => FeedTraceSink.layerLiveWithDirectSink), Match.exhaustive);
|
|
120
|
+
var AssistantTestLayerWithTriggers = (options) => Layer.mergeAll(AssistantTestLayer(options), TriggerDispatcher.layer({
|
|
121
|
+
timeControl: "manual",
|
|
122
|
+
startingTime: /* @__PURE__ */ new Date("2025-09-05T15:01:00.000Z")
|
|
123
|
+
}).pipe(Layer.provide(Registry$1.layer)), TriggerStateStore.layerMemory);
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/testing/test-agent.ts
|
|
126
|
+
/**
|
|
127
|
+
* Forks a collector over {@link AgentService.Session.subscribeEphemeral} so a test can assert the
|
|
128
|
+
* streaming path (partial → complete blocks) without a UI. The fork is scoped: use with
|
|
129
|
+
* `it.scoped` (or an explicit scope) so the subscription is interrupted on test close.
|
|
130
|
+
*/
|
|
131
|
+
var collectEphemeral = (session) => Effect.gen(function* () {
|
|
132
|
+
const partial = [];
|
|
133
|
+
const complete = [];
|
|
134
|
+
yield* session.subscribeEphemeral().pipe(Stream.runForEach((message) => Effect.sync(() => {
|
|
135
|
+
for (const event of message.events) if (Trace.isOfType(PartialBlock, event)) partial.push(event.data);
|
|
136
|
+
else if (Trace.isOfType(CompleteBlock, event)) complete.push(event.data);
|
|
137
|
+
})), Effect.forkScoped);
|
|
138
|
+
return {
|
|
139
|
+
partialBlocks: () => [...partial],
|
|
140
|
+
completeBlocks: () => [...complete]
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
var WaitForMessageTimeoutError = class extends BaseError.extend("WaitForMessageTimeoutError") {
|
|
144
|
+
constructor(timeout, options) {
|
|
145
|
+
super({
|
|
146
|
+
message: `Timed out after ${timeout}ms waiting for a matching feed message.`,
|
|
147
|
+
context: { timeout },
|
|
148
|
+
...options
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Polls the conversation feed until a message matches. Covers the gap left by
|
|
154
|
+
* `Session.waitForCompletion`, which settles when the *turn* completes — background sub-agents
|
|
155
|
+
* report back later, out of band. Polls on the real clock (not the Effect `TestClock`), so it works
|
|
156
|
+
* under `it.effect` and `it.scoped` alike.
|
|
157
|
+
*/
|
|
158
|
+
var waitForMessage = (feed, predicate, { timeout = 1e4, interval = 100 } = {}) => Effect.gen(function* () {
|
|
159
|
+
const deadline = Date.now() + timeout;
|
|
160
|
+
do {
|
|
161
|
+
const match = (yield* Feed.query(feed, Filter.type(Message.Message)).run).filter(Obj.instanceOf(Message.Message)).find(predicate);
|
|
162
|
+
if (match) return match;
|
|
163
|
+
yield* Effect.promise(() => new Promise((resolve) => setTimeout(resolve, interval)));
|
|
164
|
+
} while (Date.now() < deadline);
|
|
165
|
+
return yield* Effect.fail(new WaitForMessageTimeoutError(timeout));
|
|
166
|
+
});
|
|
167
|
+
/** Convenience predicate: any block's text content contains the substring. */
|
|
168
|
+
var messageTextIncludes = (needle) => (message) => Message.extractText(message).includes(needle);
|
|
169
|
+
//#endregion
|
|
170
|
+
//#region src/testing/ResearchService.ts
|
|
171
|
+
var ResearchService_exports = /* @__PURE__ */ __exportAll({
|
|
172
|
+
ResearchService: () => ResearchService,
|
|
173
|
+
getTestData: () => getTestData,
|
|
174
|
+
layer: () => layer
|
|
175
|
+
});
|
|
176
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/core/compute/agent-runtime/src/testing/ResearchService.ts";
|
|
177
|
+
var getTestData = () => ({
|
|
178
|
+
organizations: [
|
|
179
|
+
Organization.make({
|
|
180
|
+
name: "Cyberdyne Systems",
|
|
181
|
+
website: "https://cyberdyne.com"
|
|
182
|
+
}),
|
|
183
|
+
Organization.make({
|
|
184
|
+
name: "Acme Robotics",
|
|
185
|
+
website: "https://acmerobotics.example"
|
|
186
|
+
}),
|
|
187
|
+
Organization.make({
|
|
188
|
+
name: "Globex Research",
|
|
189
|
+
website: "https://globex.example"
|
|
190
|
+
})
|
|
191
|
+
],
|
|
192
|
+
research: {
|
|
193
|
+
"https://cyberdyne.com": `
|
|
194
|
+
Cyberdyne Systems is a company that builds AI agents.
|
|
195
|
+
They are based in San Francisco, California.
|
|
196
|
+
They were founded in 1984.
|
|
197
|
+
They are a public company.
|
|
198
|
+
They are listed on the NASDAQ under the symbol CYBR.
|
|
199
|
+
They are a member of the S&P 500 index.
|
|
200
|
+
`,
|
|
201
|
+
"https://acmerobotics.example": `
|
|
202
|
+
Acme Robotics designs industrial automation and collaborative robots.
|
|
203
|
+
They are headquartered in Austin, Texas.
|
|
204
|
+
They were founded in 2010.
|
|
205
|
+
They serve manufacturing and logistics customers worldwide.
|
|
206
|
+
`,
|
|
207
|
+
"https://globex.example": `
|
|
208
|
+
Globex Research runs applied R&D labs focused on materials science and energy storage.
|
|
209
|
+
They are based in Cambridge, Massachusetts.
|
|
210
|
+
They partner with universities and government grants programs.
|
|
211
|
+
Their flagship product line is solid-state battery prototypes for EVs.
|
|
212
|
+
`
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
var ResearchService = class extends Context.Tag("@dxos/functions-runtime/testing/ResearchService")() {};
|
|
216
|
+
var layer = Layer.effect(ResearchService, Effect.gen(function* () {
|
|
217
|
+
const taskSignal = yield* Queue.unbounded();
|
|
218
|
+
const tasks = [];
|
|
219
|
+
const complete = (task) => Effect.gen(function* () {
|
|
220
|
+
log.info("complete research", {
|
|
221
|
+
id: task.id,
|
|
222
|
+
website: task.website
|
|
223
|
+
}, {
|
|
224
|
+
"~LogMeta": "~LogMeta",
|
|
225
|
+
F: __dxlog_file,
|
|
226
|
+
L: 86,
|
|
227
|
+
S: this
|
|
228
|
+
});
|
|
229
|
+
task.state = "completed";
|
|
230
|
+
const result = getTestData().research[task.website];
|
|
231
|
+
if (!result) {
|
|
232
|
+
yield* Effect.die(/* @__PURE__ */ new Error(`No research found for ${task.website}`));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
yield* Deferred.succeed(task.deferred, result);
|
|
236
|
+
});
|
|
237
|
+
return ResearchService.of({
|
|
238
|
+
getTasks: () => tasks,
|
|
239
|
+
research: (website) => Effect.gen(function* () {
|
|
240
|
+
const id = crypto.randomUUID();
|
|
241
|
+
const task = {
|
|
242
|
+
id,
|
|
243
|
+
state: "pending",
|
|
244
|
+
website,
|
|
245
|
+
deferred: yield* Deferred.make()
|
|
246
|
+
};
|
|
247
|
+
log.info("start research", {
|
|
248
|
+
id,
|
|
249
|
+
website
|
|
250
|
+
}, {
|
|
251
|
+
"~LogMeta": "~LogMeta",
|
|
252
|
+
F: __dxlog_file,
|
|
253
|
+
L: 102,
|
|
254
|
+
S: this
|
|
255
|
+
});
|
|
256
|
+
tasks.push(task);
|
|
257
|
+
yield* Queue.offer(taskSignal, void 0);
|
|
258
|
+
return yield* Deferred.await(task.deferred).pipe(Effect.onInterrupt(() => Effect.sync(() => {
|
|
259
|
+
log.info("interrupt research", {
|
|
260
|
+
id,
|
|
261
|
+
website: task.website
|
|
262
|
+
}, {
|
|
263
|
+
"~LogMeta": "~LogMeta",
|
|
264
|
+
F: __dxlog_file,
|
|
265
|
+
L: 108,
|
|
266
|
+
S: this
|
|
267
|
+
});
|
|
268
|
+
task.state = "interrupted";
|
|
269
|
+
})));
|
|
270
|
+
}),
|
|
271
|
+
waitForTaskToAppear: () => Effect.gen(function* () {
|
|
272
|
+
while (true) {
|
|
273
|
+
if (tasks.find((t) => t.state === "pending")) return;
|
|
274
|
+
yield* Queue.take(taskSignal);
|
|
275
|
+
}
|
|
276
|
+
}),
|
|
277
|
+
completeOneTask: () => Effect.gen(function* () {
|
|
278
|
+
const task = tasks.find((t) => t.state === "pending");
|
|
279
|
+
if (!task) return;
|
|
280
|
+
yield* complete(task);
|
|
281
|
+
}),
|
|
282
|
+
completeAllTasks: () => Effect.gen(function* () {
|
|
283
|
+
while (true) {
|
|
284
|
+
const task = tasks.find((t) => t.state === "pending");
|
|
285
|
+
if (!task) return;
|
|
286
|
+
yield* complete(task);
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
});
|
|
290
|
+
}));
|
|
291
|
+
//#endregion
|
|
292
|
+
export { AssistantTestBaseLayer, AssistantTestLayer, AssistantTestLayerWithTriggers, AssistantTestServiceResolverLayer, ResearchService_exports as ResearchService, WaitForMessageTimeoutError, collectEphemeral, messageTextIncludes, prettyPrintTraceMessage, runMemoizedTests, traceFeedPrettyPrintSubscription, traceSinkPrettyLayer, waitForMessage };
|
|
293
|
+
|
|
294
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +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 { CompleteBlock } from '@dxos/assistant';\nimport { Process, Trace } from '@dxos/compute';\nimport { FeedTraceSink } from '@dxos/compute-runtime';\nimport { Database, Filter, Query } from '@dxos/echo';\n\n/**\n * Pretty-prints assistant trace messages to stdout (CompleteBlock, process spawn/exit).\n */\nexport const prettyPrintTraceMessage = (message: Trace.Message): void => {\n for (const event of message.events) {\n if (Trace.isOfType(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(queryResult.runSync().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 { Registry as AtomRegistry } from '@effect-atom/atom';\nimport * as LanguageModel from '@effect/ai/LanguageModel';\nimport * as KeyValueStore from '@effect/platform/KeyValueStore';\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';\n\nimport { AiService, OpaqueToolkit, Provider } from '@dxos/ai';\nimport { TestAiService } from '@dxos/ai/testing';\nimport { Harness } from '@dxos/assistant';\nimport {\n AgentService,\n Credential,\n Instructions,\n Operation,\n OperationHandlerSet,\n Process,\n ServiceNotAvailableError,\n ServiceResolver,\n Skill,\n Trace,\n Trigger,\n} from '@dxos/compute';\nimport {\n FeedTraceSink,\n ProcessManager,\n ProcessMonitor,\n RemoteProcessManager,\n RemoteTraceMonitor,\n TriggerDispatcher,\n TriggerStateStore,\n configuredCredentialsLayer,\n} from '@dxos/compute-runtime';\nimport { TestDatabaseLayer } from '@dxos/compute-runtime/testing';\nimport { Database, Feed, 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';\nimport { traceSinkPrettyLayer } from './trace-pretty-print';\n\ninterface TestLayerOptions {\n aiServicePreset?: 'direct' | 'edge-local' | 'edge-remote' | 'ollama';\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.AgentServiceOptions;\n\n /**\n * Extra services to make available in the service resolver.\n * Operations can depend on those services.\n */\n extraServices?: Layer.Layer<never, never, never>;\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 | ProcessManager.ProcessOperationInvoker.Service\n | Process.ProcessMonitorService\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-4-8.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.AgentServiceOptions = { ...options.agent };\n agentOptions.model ??= 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(ProcessManager.ProcessOperationInvoker.layer),\n Layer.provideMerge(ProcessMonitor.layer),\n Layer.provideMerge(RemoteProcessManager.layerNoop),\n Layer.provideMerge(RemoteTraceMonitor.layerNoop),\n Layer.provideMerge(AgentServiceRuntime.layer(agentOptions)),\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.model(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.Tag.Service<ProcessManager.Service>;\n}\n\n/** Late-bound reference to the {@link AgentService.AgentService}, filled once the service is built. */\ninterface AgentServiceHolder {\n current?: Context.Tag.Service<AgentService.AgentService>;\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.scoped(\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 extraServicesRt = yield* Layer.toRuntime(extraServices);\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 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 ServiceNotAvailableError(ProcessManager.Service.key));\n }\n const runtime = yield* Effect.runtime<Database.Service>();\n return yield* Harness.make({ conversation: context.conversation, processManager, runtime });\n }).pipe(Effect.provide(services)),\n ),\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 ServiceNotAvailableError(AgentService.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(extraServicesRt.context),\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 Trigger.Trigger,\n Tag.Tag,\n );\n types = Array.dedupeWith(types, (a, b) => Type.getTypename(a) === Type.getTypename(b));\n\n return Layer.empty.pipe(\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(handlers.map(Operation.serialize));\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\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.mergeAll(\n AssistantTestLayer(options),\n TriggerDispatcher.layer({ timeControl: 'manual', startingTime: new Date('2025-09-05T15:01:00.000Z') }).pipe(\n Layer.provide(AtomRegistry.layer),\n ),\n TriggerStateStore.layerMemory,\n ) as any;\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 { CompleteBlock, PartialBlock } from '@dxos/assistant';\nimport { type AgentService, Trace } from '@dxos/compute';\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 `PartialBlock` payloads observed so far, in arrival order. */\n partialBlocks: () => readonly Trace.PayloadType<typeof PartialBlock>[];\n /** Snapshot of `CompleteBlock` payloads observed so far, in arrival order. */\n completeBlocks: () => readonly Trace.PayloadType<typeof 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.scoped` (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 PartialBlock>[] = [];\n const complete: Trace.PayloadType<typeof CompleteBlock>[] = [];\n yield* session.subscribeEphemeral().pipe(\n Stream.runForEach((message) =>\n Effect.sync(() => {\n for (const event of message.events) {\n if (Trace.isOfType(PartialBlock, event)) {\n partial.push(event.data);\n } else if (Trace.isOfType(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.scoped` 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.Tag('@dxos/functions-runtime/testing/ResearchService')<\n ResearchService,\n Service\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 yield* Effect.die(new Error(`No research found for ${task.website}`));\n return;\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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"}
|
|
@@ -24,10 +24,6 @@ export interface AgentServiceOptions {
|
|
|
24
24
|
* Default provider used to resolve the model for sessions that don't specify one explicitly.
|
|
25
25
|
*/
|
|
26
26
|
provider?: DXN.DXN;
|
|
27
|
-
/**
|
|
28
|
-
* Provider for space-level MCP server configs.
|
|
29
|
-
*/
|
|
30
|
-
getMcpServers?: () => McpServer.McpServer[];
|
|
31
27
|
/**
|
|
32
28
|
* If true, long-running tool calls are moved to the background and the agent is notified
|
|
33
29
|
* asynchronously when they complete. Currently unstable — disabled by default.
|
|
@@ -40,6 +36,10 @@ export interface AgentServiceOptions {
|
|
|
40
36
|
* child processes and folds their results back into the conversation. Absent — a plain agent.
|
|
41
37
|
*/
|
|
42
38
|
delegationStrategy?: DelegationStrategy;
|
|
39
|
+
/**
|
|
40
|
+
* Provider for space-level MCP server configs.
|
|
41
|
+
*/
|
|
42
|
+
getMcpServers?: () => McpServer.McpServer[];
|
|
43
43
|
}
|
|
44
44
|
export declare const layer: (opts?: AgentServiceOptions) => Layer.Layer<AgentService, never, ProcessManager.Service>;
|
|
45
45
|
//# sourceMappingURL=AgentService.d.ts.map
|
|
@@ -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;
|
|
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;AAItC,OAAO,EAAE,SAAS,EAAW,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,YAAY,EAGZ,KAAK,OAAO,EAEb,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAc,QAAQ,EAAQ,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EAAE,GAAG,EAAO,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAYhE,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,eAAO,MAAM,aAAa,EAAE,CAC1B,IAAI,CAAC,EAAE,oBAAoB,KACxB,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,GAAG,YAAY,CAmBlF,CAAC;AAElB,MAAM,WAAW,mBAAmB;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,KAAK,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC;IAEhB;;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;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,SAAS,CAAC,SAAS,EAAE,CAAC;CAC7C;AAED,eAAO,MAAM,KAAK,UAAW,mBAAmB,KAAG,KAAK,CAAC,KAAK,CAAC,YAAY,EAAE,KAAK,EAAE,cAAc,CAAC,OAAO,CAwIvG,CAAC"}
|