@assemblyline-agents/runtime 0.1.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/LICENSE +21 -0
- package/README.md +19 -0
- package/dist/agent-harness.d.ts +108 -0
- package/dist/agent-harness.d.ts.map +1 -0
- package/dist/agent-harness.js +2 -0
- package/dist/agent-harness.js.map +1 -0
- package/dist/attachments-legacy.d.ts +17 -0
- package/dist/attachments-legacy.d.ts.map +1 -0
- package/dist/attachments-legacy.js +273 -0
- package/dist/attachments-legacy.js.map +1 -0
- package/dist/attachments.d.ts +49 -0
- package/dist/attachments.d.ts.map +1 -0
- package/dist/attachments.js +832 -0
- package/dist/attachments.js.map +1 -0
- package/dist/builtin-tool-executors.d.ts +96 -0
- package/dist/builtin-tool-executors.d.ts.map +1 -0
- package/dist/builtin-tool-executors.js +501 -0
- package/dist/builtin-tool-executors.js.map +1 -0
- package/dist/builtin-tools.d.ts +30 -0
- package/dist/builtin-tools.d.ts.map +1 -0
- package/dist/builtin-tools.js +690 -0
- package/dist/builtin-tools.js.map +1 -0
- package/dist/capability-catalog.d.ts +27 -0
- package/dist/capability-catalog.d.ts.map +1 -0
- package/dist/capability-catalog.js +193 -0
- package/dist/capability-catalog.js.map +1 -0
- package/dist/channel-http-util.d.ts +34 -0
- package/dist/channel-http-util.d.ts.map +1 -0
- package/dist/channel-http-util.js +93 -0
- package/dist/channel-http-util.js.map +1 -0
- package/dist/channel-ingress.d.ts +56 -0
- package/dist/channel-ingress.d.ts.map +1 -0
- package/dist/channel-ingress.js +273 -0
- package/dist/channel-ingress.js.map +1 -0
- package/dist/channel.d.ts +146 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +2 -0
- package/dist/channel.js.map +1 -0
- package/dist/checkpoints.d.ts +34 -0
- package/dist/checkpoints.d.ts.map +1 -0
- package/dist/checkpoints.js +86 -0
- package/dist/checkpoints.js.map +1 -0
- package/dist/code-mode.d.ts +20 -0
- package/dist/code-mode.d.ts.map +1 -0
- package/dist/code-mode.js +658 -0
- package/dist/code-mode.js.map +1 -0
- package/dist/computer-relay-protocol.d.ts +36 -0
- package/dist/computer-relay-protocol.d.ts.map +1 -0
- package/dist/computer-relay-protocol.js +127 -0
- package/dist/computer-relay-protocol.js.map +1 -0
- package/dist/concurrency.d.ts +68 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +193 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/connection-auth-util.d.ts +56 -0
- package/dist/connection-auth-util.d.ts.map +1 -0
- package/dist/connection-auth-util.js +154 -0
- package/dist/connection-auth-util.js.map +1 -0
- package/dist/connection-clients.d.ts +50 -0
- package/dist/connection-clients.d.ts.map +1 -0
- package/dist/connection-clients.js +402 -0
- package/dist/connection-clients.js.map +1 -0
- package/dist/connection-stores.d.ts +108 -0
- package/dist/connection-stores.d.ts.map +1 -0
- package/dist/connection-stores.js +127 -0
- package/dist/connection-stores.js.map +1 -0
- package/dist/connection-util.d.ts +27 -0
- package/dist/connection-util.d.ts.map +1 -0
- package/dist/connection-util.js +118 -0
- package/dist/connection-util.js.map +1 -0
- package/dist/connections.d.ts +152 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +838 -0
- package/dist/connections.js.map +1 -0
- package/dist/content-capture.d.ts +32 -0
- package/dist/content-capture.d.ts.map +1 -0
- package/dist/content-capture.js +77 -0
- package/dist/content-capture.js.map +1 -0
- package/dist/context-policy-util.d.ts +45 -0
- package/dist/context-policy-util.d.ts.map +1 -0
- package/dist/context-policy-util.js +120 -0
- package/dist/context-policy-util.js.map +1 -0
- package/dist/conversation-context.d.ts +55 -0
- package/dist/conversation-context.d.ts.map +1 -0
- package/dist/conversation-context.js +179 -0
- package/dist/conversation-context.js.map +1 -0
- package/dist/conversation-transcript.d.ts +49 -0
- package/dist/conversation-transcript.d.ts.map +1 -0
- package/dist/conversation-transcript.js +77 -0
- package/dist/conversation-transcript.js.map +1 -0
- package/dist/conversation-turn-dispatch.d.ts +46 -0
- package/dist/conversation-turn-dispatch.d.ts.map +1 -0
- package/dist/conversation-turn-dispatch.js +201 -0
- package/dist/conversation-turn-dispatch.js.map +1 -0
- package/dist/delivery-queue.d.ts +89 -0
- package/dist/delivery-queue.d.ts.map +1 -0
- package/dist/delivery-queue.js +244 -0
- package/dist/delivery-queue.js.map +1 -0
- package/dist/delivery-send.d.ts +44 -0
- package/dist/delivery-send.d.ts.map +1 -0
- package/dist/delivery-send.js +494 -0
- package/dist/delivery-send.js.map +1 -0
- package/dist/env-config.d.ts +6 -0
- package/dist/env-config.d.ts.map +1 -0
- package/dist/env-config.js +27 -0
- package/dist/env-config.js.map +1 -0
- package/dist/eval-run-options.d.ts +37 -0
- package/dist/eval-run-options.d.ts.map +1 -0
- package/dist/eval-run-options.js +106 -0
- package/dist/eval-run-options.js.map +1 -0
- package/dist/harness-continuation.d.ts +54 -0
- package/dist/harness-continuation.d.ts.map +1 -0
- package/dist/harness-continuation.js +58 -0
- package/dist/harness-continuation.js.map +1 -0
- package/dist/harness-loop.d.ts +110 -0
- package/dist/harness-loop.d.ts.map +1 -0
- package/dist/harness-loop.js +575 -0
- package/dist/harness-loop.js.map +1 -0
- package/dist/hook-dispatch.d.ts +19 -0
- package/dist/hook-dispatch.d.ts.map +1 -0
- package/dist/hook-dispatch.js +37 -0
- package/dist/hook-dispatch.js.map +1 -0
- package/dist/http.d.ts +26 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +114 -0
- package/dist/http.js.map +1 -0
- package/dist/in-memory-conversation-turn-store.d.ts +29 -0
- package/dist/in-memory-conversation-turn-store.d.ts.map +1 -0
- package/dist/in-memory-conversation-turn-store.js +166 -0
- package/dist/in-memory-conversation-turn-store.js.map +1 -0
- package/dist/in-memory-run-store.d.ts +39 -0
- package/dist/in-memory-run-store.d.ts.map +1 -0
- package/dist/in-memory-run-store.js +332 -0
- package/dist/in-memory-run-store.js.map +1 -0
- package/dist/in-memory-sandbox-session-store.d.ts +33 -0
- package/dist/in-memory-sandbox-session-store.d.ts.map +1 -0
- package/dist/in-memory-sandbox-session-store.js +186 -0
- package/dist/in-memory-sandbox-session-store.js.map +1 -0
- package/dist/in-memory-small-stores.d.ts +117 -0
- package/dist/in-memory-small-stores.d.ts.map +1 -0
- package/dist/in-memory-small-stores.js +340 -0
- package/dist/in-memory-small-stores.js.map +1 -0
- package/dist/in-memory-usage-store.d.ts +15 -0
- package/dist/in-memory-usage-store.d.ts.map +1 -0
- package/dist/in-memory-usage-store.js +49 -0
- package/dist/in-memory-usage-store.js.map +1 -0
- package/dist/index.d.ts +467 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2046 -0
- package/dist/index.js.map +1 -0
- package/dist/json-util.d.ts +19 -0
- package/dist/json-util.d.ts.map +1 -0
- package/dist/json-util.js +59 -0
- package/dist/json-util.js.map +1 -0
- package/dist/local-sandbox.d.ts +16 -0
- package/dist/local-sandbox.d.ts.map +1 -0
- package/dist/local-sandbox.js +327 -0
- package/dist/local-sandbox.js.map +1 -0
- package/dist/logging.d.ts +16 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +41 -0
- package/dist/logging.js.map +1 -0
- package/dist/mcp-client.d.ts +27 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +169 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/model-harnesses.d.ts +4 -0
- package/dist/model-harnesses.d.ts.map +1 -0
- package/dist/model-harnesses.js +6 -0
- package/dist/model-harnesses.js.map +1 -0
- package/dist/model-media.d.ts +36 -0
- package/dist/model-media.d.ts.map +1 -0
- package/dist/model-media.js +234 -0
- package/dist/model-media.js.map +1 -0
- package/dist/operator-controls.d.ts +31 -0
- package/dist/operator-controls.d.ts.map +1 -0
- package/dist/operator-controls.js +71 -0
- package/dist/operator-controls.js.map +1 -0
- package/dist/pi-agent-harness.d.ts +40 -0
- package/dist/pi-agent-harness.d.ts.map +1 -0
- package/dist/pi-agent-harness.js +222 -0
- package/dist/pi-agent-harness.js.map +1 -0
- package/dist/pi-harness.d.ts +42 -0
- package/dist/pi-harness.d.ts.map +1 -0
- package/dist/pi-harness.js +142 -0
- package/dist/pi-harness.js.map +1 -0
- package/dist/relay-mcp-client.d.ts +17 -0
- package/dist/relay-mcp-client.d.ts.map +1 -0
- package/dist/relay-mcp-client.js +119 -0
- package/dist/relay-mcp-client.js.map +1 -0
- package/dist/replay-resume.d.ts +107 -0
- package/dist/replay-resume.d.ts.map +1 -0
- package/dist/replay-resume.js +495 -0
- package/dist/replay-resume.js.map +1 -0
- package/dist/resource-projection-util.d.ts +58 -0
- package/dist/resource-projection-util.d.ts.map +1 -0
- package/dist/resource-projection-util.js +298 -0
- package/dist/resource-projection-util.js.map +1 -0
- package/dist/resource-projection.d.ts +45 -0
- package/dist/resource-projection.d.ts.map +1 -0
- package/dist/resource-projection.js +481 -0
- package/dist/resource-projection.js.map +1 -0
- package/dist/run-heartbeat.d.ts +34 -0
- package/dist/run-heartbeat.d.ts.map +1 -0
- package/dist/run-heartbeat.js +62 -0
- package/dist/run-heartbeat.js.map +1 -0
- package/dist/run-outcome.d.ts +47 -0
- package/dist/run-outcome.d.ts.map +1 -0
- package/dist/run-outcome.js +92 -0
- package/dist/run-outcome.js.map +1 -0
- package/dist/run-recovery.d.ts +117 -0
- package/dist/run-recovery.d.ts.map +1 -0
- package/dist/run-recovery.js +466 -0
- package/dist/run-recovery.js.map +1 -0
- package/dist/run-resolver.d.ts +35 -0
- package/dist/run-resolver.d.ts.map +1 -0
- package/dist/run-resolver.js +84 -0
- package/dist/run-resolver.js.map +1 -0
- package/dist/run-stream.d.ts +37 -0
- package/dist/run-stream.d.ts.map +1 -0
- package/dist/run-stream.js +78 -0
- package/dist/run-stream.js.map +1 -0
- package/dist/runs-query.d.ts +29 -0
- package/dist/runs-query.d.ts.map +1 -0
- package/dist/runs-query.js +142 -0
- package/dist/runs-query.js.map +1 -0
- package/dist/runtime-bundle.d.ts +3 -0
- package/dist/runtime-bundle.d.ts.map +1 -0
- package/dist/runtime-bundle.js +18 -0
- package/dist/runtime-bundle.js.map +1 -0
- package/dist/runtime-types.d.ts +397 -0
- package/dist/runtime-types.d.ts.map +1 -0
- package/dist/runtime-types.js +2 -0
- package/dist/runtime-types.js.map +1 -0
- package/dist/runtime-util.d.ts +45 -0
- package/dist/runtime-util.d.ts.map +1 -0
- package/dist/runtime-util.js +116 -0
- package/dist/runtime-util.js.map +1 -0
- package/dist/sandbox-cli-client.d.ts +20 -0
- package/dist/sandbox-cli-client.d.ts.map +1 -0
- package/dist/sandbox-cli-client.js +97 -0
- package/dist/sandbox-cli-client.js.map +1 -0
- package/dist/sandbox-fs.d.ts +56 -0
- package/dist/sandbox-fs.d.ts.map +1 -0
- package/dist/sandbox-fs.js +276 -0
- package/dist/sandbox-fs.js.map +1 -0
- package/dist/sandbox-session-key.d.ts +8 -0
- package/dist/sandbox-session-key.d.ts.map +1 -0
- package/dist/sandbox-session-key.js +32 -0
- package/dist/sandbox-session-key.js.map +1 -0
- package/dist/sandbox-snapshot-policy.d.ts +27 -0
- package/dist/sandbox-snapshot-policy.d.ts.map +1 -0
- package/dist/sandbox-snapshot-policy.js +94 -0
- package/dist/sandbox-snapshot-policy.js.map +1 -0
- package/dist/sandbox-sync-worker.d.ts +63 -0
- package/dist/sandbox-sync-worker.d.ts.map +1 -0
- package/dist/sandbox-sync-worker.js +448 -0
- package/dist/sandbox-sync-worker.js.map +1 -0
- package/dist/schedule-execution.d.ts +59 -0
- package/dist/schedule-execution.d.ts.map +1 -0
- package/dist/schedule-execution.js +951 -0
- package/dist/schedule-execution.js.map +1 -0
- package/dist/scheduler.d.ts +19 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +38 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/security.d.ts +20 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +145 -0
- package/dist/security.js.map +1 -0
- package/dist/self-improvement.d.ts +245 -0
- package/dist/self-improvement.d.ts.map +1 -0
- package/dist/self-improvement.js +554 -0
- package/dist/self-improvement.js.map +1 -0
- package/dist/source-loader.d.ts +19 -0
- package/dist/source-loader.d.ts.map +1 -0
- package/dist/source-loader.js +160 -0
- package/dist/source-loader.js.map +1 -0
- package/dist/state-store-helpers.d.ts +28 -0
- package/dist/state-store-helpers.d.ts.map +1 -0
- package/dist/state-store-helpers.js +164 -0
- package/dist/state-store-helpers.js.map +1 -0
- package/dist/state-stores.d.ts +25 -0
- package/dist/state-stores.d.ts.map +1 -0
- package/dist/state-stores.js +157 -0
- package/dist/state-stores.js.map +1 -0
- package/dist/state.d.ts +736 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +46 -0
- package/dist/state.js.map +1 -0
- package/dist/storage.d.ts +188 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +752 -0
- package/dist/storage.js.map +1 -0
- package/dist/subagent-execution.d.ts +80 -0
- package/dist/subagent-execution.d.ts.map +1 -0
- package/dist/subagent-execution.js +135 -0
- package/dist/subagent-execution.js.map +1 -0
- package/dist/telemetry.d.ts +49 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +60 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/tool-apis.d.ts +22 -0
- package/dist/tool-apis.d.ts.map +1 -0
- package/dist/tool-apis.js +344 -0
- package/dist/tool-apis.js.map +1 -0
- package/dist/tool-execution.d.ts +143 -0
- package/dist/tool-execution.d.ts.map +1 -0
- package/dist/tool-execution.js +573 -0
- package/dist/tool-execution.js.map +1 -0
- package/dist/trusted-attachments.d.ts +20 -0
- package/dist/trusted-attachments.d.ts.map +1 -0
- package/dist/trusted-attachments.js +276 -0
- package/dist/trusted-attachments.js.map +1 -0
- package/dist/usage-accounting.d.ts +37 -0
- package/dist/usage-accounting.d.ts.map +1 -0
- package/dist/usage-accounting.js +181 -0
- package/dist/usage-accounting.js.map +1 -0
- package/dist/usage-budget.d.ts +29 -0
- package/dist/usage-budget.d.ts.map +1 -0
- package/dist/usage-budget.js +145 -0
- package/dist/usage-budget.js.map +1 -0
- package/dist/usage-reconciliation.d.ts +76 -0
- package/dist/usage-reconciliation.d.ts.map +1 -0
- package/dist/usage-reconciliation.js +463 -0
- package/dist/usage-reconciliation.js.map +1 -0
- package/dist/usage-records.d.ts +24 -0
- package/dist/usage-records.d.ts.map +1 -0
- package/dist/usage-records.js +445 -0
- package/dist/usage-records.js.map +1 -0
- package/package.json +51 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2046 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { builtInToolDefinition } from "./builtin-tools.js";
|
|
4
|
+
export { builtInToolDefaults } from "./builtin-tools.js";
|
|
5
|
+
import { createHookDispatcher } from "./hook-dispatch.js";
|
|
6
|
+
import { resolveEvalToolStub, validateEvalRunOptions } from "./eval-run-options.js";
|
|
7
|
+
import { resolveRunCapabilitiesImpl } from "./run-resolver.js";
|
|
8
|
+
import { AgentSourceModuleLoader } from "./source-loader.js";
|
|
9
|
+
import { compiledChannelProvider, providerIngressSecurityError, providerIngressSecurityWarnings, resolveCoreToolPolicy, trustedAttachmentProviderForTurn } from "./security.js";
|
|
10
|
+
export { constantTimeSecretEqual } from "./security.js";
|
|
11
|
+
export { RUN_STREAM_TERMINAL_EVENTS } from "./run-stream.js";
|
|
12
|
+
export { failRun } from "./run-outcome.js";
|
|
13
|
+
import { OPENEVE_MANIFEST_SCHEMA_VERSION, applyEnvAliases, hasCurrentSandboxFilesystemContract, sandboxFilesystemContractMetadata } from "@assemblyline-agents/core";
|
|
14
|
+
import { resolveBooleanEnv, resolveNonNegativeIntegerEnv, resolvePositiveIntegerEnv } from "./env-config.js";
|
|
15
|
+
import { RunEventBus, withRunEventPublishing } from "./run-stream.js";
|
|
16
|
+
import { handleRunExecutionError, logTerminalRunEvent, settleCompletionBoundaryControlImpl } from "./run-outcome.js";
|
|
17
|
+
import { registerRunAbortController, startRunHeartbeatImpl } from "./run-heartbeat.js";
|
|
18
|
+
import { redactTruncateJson } from "./content-capture.js";
|
|
19
|
+
import { sandboxSessionKeyForRun } from "./sandbox-session-key.js";
|
|
20
|
+
export { sandboxSessionKeyForRun } from "./sandbox-session-key.js";
|
|
21
|
+
import { InMemoryConnectionAuthorizationSessionStore, InMemoryConnectionGrantStore, materializeConnectionCredentialsIntoSandbox } from "./connections.js";
|
|
22
|
+
import { InMemoryConnectionDefinitionStore, InMemoryScheduleStore, InMemorySkillStore, compiledConnectionFromStored, isHostAllowed, liveSkills, resolveSkillsConfig, resolveSchedulesConfig, resolveConnectionsConfig, seedSkills, writeSkill } from "./self-improvement.js";
|
|
23
|
+
import { materializeTurnAttachments } from "./attachments.js";
|
|
24
|
+
// Attachment helpers for channel modules implementing `resolveAttachment`.
|
|
25
|
+
export { attachmentFetchTimeoutMs, attachmentRemoteUrl, attachmentTrustedForProvider, firstDownloadableUrl } from "./attachments.js";
|
|
26
|
+
import { LocalSandboxAdapter } from "./local-sandbox.js";
|
|
27
|
+
import { schedulerAdapterForKind } from "./scheduler.js";
|
|
28
|
+
import { isTelemetrySink, telemetrySinkFromSetupResult } from "./telemetry.js";
|
|
29
|
+
import { InMemoryStateAdapter, LocalBlobAdapter, StateMemoryStore, memoryBodyText, positiveLimit } from "./storage.js";
|
|
30
|
+
import { createJsonConsoleLogger, normalizeLogLevel } from "./logging.js";
|
|
31
|
+
import { runDueDeliveriesImpl, startDeliveryWorkerImpl } from "./delivery-queue.js";
|
|
32
|
+
import { recoverIncompleteRunsImpl, startBackgroundWorkersImpl } from "./run-recovery.js";
|
|
33
|
+
import { captureSandboxSnapshotImpl, disposeSandboxSessionImpl, inspectSandboxSyncJobImpl, retrySandboxSyncJobImpl, runDueSandboxSyncJobsImpl, sandboxSyncDiagnosticsImpl, startSandboxSyncWorkerImpl } from "./sandbox-sync-worker.js";
|
|
34
|
+
import { beginChannelTurnImpl, completeRunImpl, enqueueSandboxSyncAfterDeliveryImpl, latestRunFailureMessageImpl, recordChannelTurnStartImpl, sendDeliveryImpl, stopUnclaimedChannelTurnImpl, stopChannelTurnImpl } from "./delivery-send.js";
|
|
35
|
+
import { backfillMemoryDocumentsFromFileIndexesImpl, hydrateLogicalPathForToolImpl, listResourcesForRunImpl, memoryScopeForRunImpl, projectResourcesForRunImpl, projectSkillIntoSandboxImpl, readResourceForRunImpl, readSandboxTombstonesWithMissingProjectedFilesImpl, recordSandboxTombstoneImpl, runMemoryEmbeddingBackfillImpl } from "./resource-projection.js";
|
|
36
|
+
import { beginConnectionAuthorizationImpl, createConnectionRegistryForRunImpl, createConnectionRegistryForSessionImpl, createConnectionRegistryImpl, executeConnectionToolWithRecordImpl, skillLoadDetailsImpl } from "./builtin-tool-executors.js";
|
|
37
|
+
import { createMemoryToolApiImpl, createResourceToolApiImpl, durableStepImpl } from "./tool-apis.js";
|
|
38
|
+
import { executeToolImpl, executeToolWithRecordImpl, harnessExecuteToolImpl, modelToolsImpl, selectToolImpl, visibleToolSetImpl, wrapSandboxImpl } from "./tool-execution.js";
|
|
39
|
+
import { dispatchAutomationEventImpl, normalizeScheduleTriggerDefinitionImpl, registerManifestSchedulesImpl, runDueSchedulesImpl, startSchedulerPollingLoopImpl } from "./schedule-execution.js";
|
|
40
|
+
import { completeConnectionAuthorizationCallbackImpl, replayImpl, resumeApprovalNowImpl, resumeHarnessLoopImpl, resumeInputNowImpl, resumeRunFromContinuationImpl, resumeSuspendedNowImpl } from "./replay-resume.js";
|
|
41
|
+
import { readSubagentImpl, runSubagentImpl, sendSubagentFollowupImpl } from "./subagent-execution.js";
|
|
42
|
+
import { createHarnessContextImpl, DEFAULT_MAX_MODEL_ITERATIONS, DEFAULT_OUTPUT_VALIDATION_MAX_RETRIES, executeHarnessTurnImpl, persistHarnessContinuationImpl, piHarnessImpl, resolveAgentHarnessImpl, runHarnessLoopImpl } from "./harness-loop.js";
|
|
43
|
+
import { getAgentControlImpl, requestRunControlImpl, setAgentEnabledImpl, setAgentMaintenanceImpl } from "./operator-controls.js";
|
|
44
|
+
import { acceptChannelTurnImpl, channelAttachmentResolverImpl, dispatchHttpChannelImpl, loadChannelModuleImpl, startChannelIngressImpl } from "./channel-ingress.js";
|
|
45
|
+
import { augmentChannelContextImpl, buildContextBundleImpl, prepareConversationImpl, recentHistoryImpl } from "./conversation-context.js";
|
|
46
|
+
import { loadResumableConversationTranscriptImpl } from "./conversation-transcript.js";
|
|
47
|
+
import { ConversationTurnDispatcher } from "./conversation-turn-dispatch.js";
|
|
48
|
+
import { instructionsForRunTargetImpl } from "./run-resolver.js";
|
|
49
|
+
import { emitTelemetrySpanImpl, runSpanAttributesImpl } from "./telemetry.js";
|
|
50
|
+
import { normalizeRuntimeState } from "./state-stores.js";
|
|
51
|
+
import { COMPACTABLE_ACTIVE_CHECKPOINT_NAMES, checkpointDataForStorage as checkpointDataForBlobStorage, emptyCheckpointRetentionResult, hydrateCheckpointData as hydrateCheckpointDataFromBlob, resolveCheckpointRetentionPolicy } from "./checkpoints.js";
|
|
52
|
+
// State record types, capability facets (RunStore & friends), the
|
|
53
|
+
// StateAdapter intersection, StateStores, and the capability guards.
|
|
54
|
+
export * from "./state.js";
|
|
55
|
+
export { evalRunOptionsForRun, validateEvalRunOptions } from "./eval-run-options.js";
|
|
56
|
+
export { InMemoryConversationStore, InMemoryConversationTurnStore, InMemoryFileIndexStore, InMemoryMemoryStateStore, InMemoryRunStore, InMemorySandboxSessionStore, InMemoryScheduleStateStore, InMemoryUsageStore, composeStateStores, normalizeRuntimeState } from "./state-stores.js";
|
|
57
|
+
export { applyDeliveryPatch, createDeliveryRecord, deliveryQueueRetryDelayMs, isDeliveryDue, normalizeDeliveryRecord, stateSupportsDeliveryQueue } from "./delivery-queue.js";
|
|
58
|
+
export { defaultRunStaleAfterMs } from "./run-recovery.js";
|
|
59
|
+
export { BoundedSemaphore, RunCapacityError, retryAfterSeconds } from "./concurrency.js";
|
|
60
|
+
import { BoundedSemaphore, RunCapacityError } from "./concurrency.js";
|
|
61
|
+
import { DEFAULT_MODEL_OUTPUT_MAX_CHARS } from "@assemblyline-agents/core";
|
|
62
|
+
export { FileConnectionAuthorizationSessionStore, FileConnectionGrantStore, InMemoryConnectionAuthorizationSessionStore, InMemoryConnectionGrantStore, RuntimeConnectionRegistry, connectionToolAccess } from "./connections.js";
|
|
63
|
+
export { FileConnectionDefinitionStore, FileScheduleStore, FileSkillStore, InMemoryConnectionDefinitionStore, InMemoryScheduleStore, InMemorySkillStore, computeNextRun, resolveSkillsConfig, resolveSchedulesConfig, resolveConnectionsConfig } from "./self-improvement.js";
|
|
64
|
+
export { LocalSandboxAdapter } from "./local-sandbox.js";
|
|
65
|
+
export { FileMemoryStore, FileStateAdapter, InMemoryMemoryStore, InMemoryStateAdapter, LocalBlobAdapter, StateMemoryStore } from "./storage.js";
|
|
66
|
+
export { gatewaySchedulerAdapter, localSchedulerAdapter, postgresSchedulerAdapter, schedulerAdapterForKind } from "./scheduler.js";
|
|
67
|
+
export { createOpenTelemetrySink } from "./telemetry.js";
|
|
68
|
+
export { createJsonConsoleLogger, noopLogger, normalizeLogLevel } from "./logging.js";
|
|
69
|
+
export { capabilityCatalogForManifest, capabilityForModel, capabilityMatchesId, connectionSearchResultForModel, normalizeCapabilityKind, normalizeCapabilityRouterInput, normalizeDeferredToolSearchInput, routerShouldSearchConnections, scoreCapability, searchCapabilityCatalog, tokenizeCapabilityQuery } from "./capability-catalog.js";
|
|
70
|
+
export { fetchJson, fetchWithPolicy, readBodyCapped, retryAfterMs, HttpResponseTooLargeError } from "./http.js";
|
|
71
|
+
import { hydrateSandboxFilesystem, memoryPathFromSandboxRelativePath, scanSandboxFiles, visibleToolsForSkills } from "./sandbox-fs.js";
|
|
72
|
+
export { buildDefaultContextBundle, hydrateSandboxFilesystem, syncSandboxFilesystem, visibleToolsForSkills } from "./sandbox-fs.js";
|
|
73
|
+
export { queryAgentRuns } from "./runs-query.js";
|
|
74
|
+
export { UsageAccountingError, createUsageRecord, matchesUsageQuery, microsToUsd, queryUsageRecords, reconcileUsageRecord, sha256Json, summarizeUsageRecords, usageTokensAreAuthoritative, usageRecordInput, usdToMicros } from "./usage-records.js";
|
|
75
|
+
export { reconcileOpenAIOrganization, reconcileOpenRouterUsage, usageReconciliationReport } from "./usage-reconciliation.js";
|
|
76
|
+
import { isValidSandboxSkillBody, resolveResourceProjectionPolicy, sandboxFileContentsToUtf8, sha256Text, skillNameFromSandboxRelativePath, skillNameFromSkillPath } from "./resource-projection-util.js";
|
|
77
|
+
import { resolveSandboxSnapshotPolicy } from "./sandbox-snapshot-policy.js";
|
|
78
|
+
import { inferToolInput } from "./channel-http-util.js";
|
|
79
|
+
import { connectionPrincipalKeyForGrant, durableAgentScopeForManifest, isInstrumentationDefinition, normalizeCapturePolicy, randomHex, stringValue, timestamp, } from "./runtime-util.js";
|
|
80
|
+
export { currentModulePath, durableAgentScopeForManifest } from "./runtime-util.js";
|
|
81
|
+
export { loadRuntimeBundle } from "./runtime-bundle.js";
|
|
82
|
+
export class OpenEveRuntime {
|
|
83
|
+
manifest;
|
|
84
|
+
state;
|
|
85
|
+
runEventBus = new RunEventBus();
|
|
86
|
+
blob;
|
|
87
|
+
sandbox;
|
|
88
|
+
scheduler;
|
|
89
|
+
deliveryMode;
|
|
90
|
+
toolStubs;
|
|
91
|
+
/** Per-run {results:[...]} stub cursors; in-memory by design (see eval-run-options.ts). */
|
|
92
|
+
evalStubCursors = new Map();
|
|
93
|
+
/** @deprecated See {@link RuntimeOptions.models}. */
|
|
94
|
+
models;
|
|
95
|
+
agentHarnessOverride;
|
|
96
|
+
modelHarnesses;
|
|
97
|
+
defaultAgentHarness;
|
|
98
|
+
checkpointEveryIteration;
|
|
99
|
+
checkpointRetention;
|
|
100
|
+
checkpointBlobStorageEnabled;
|
|
101
|
+
devMode;
|
|
102
|
+
sourceBundle;
|
|
103
|
+
connections;
|
|
104
|
+
env;
|
|
105
|
+
fetch;
|
|
106
|
+
logger;
|
|
107
|
+
connectionGrantStore;
|
|
108
|
+
connectionAuthorizationSessionStore;
|
|
109
|
+
connectionCallbackBaseUrl;
|
|
110
|
+
skillStore;
|
|
111
|
+
memoryStore;
|
|
112
|
+
scheduleStore;
|
|
113
|
+
connectionDefinitionStore;
|
|
114
|
+
skillsConfig;
|
|
115
|
+
schedulesConfig;
|
|
116
|
+
connectionsConfig;
|
|
117
|
+
skillsSeeded = false;
|
|
118
|
+
skillScopeMigrated = false;
|
|
119
|
+
connectionScopeMigrated = false;
|
|
120
|
+
dynamicConnectionsCache;
|
|
121
|
+
schedulerEnabled;
|
|
122
|
+
schedulerTickMs;
|
|
123
|
+
scheduleMaxConsecutiveFailures;
|
|
124
|
+
now;
|
|
125
|
+
sandboxSnapshotPolicy;
|
|
126
|
+
sandboxSyncInline;
|
|
127
|
+
sandboxSyncLeaseMs;
|
|
128
|
+
sandboxSyncBatchSize;
|
|
129
|
+
sandboxSyncMaxAttempts;
|
|
130
|
+
deliveryQueueLeaseMs;
|
|
131
|
+
toolOutputMaxChars;
|
|
132
|
+
toolTimeoutMs;
|
|
133
|
+
deliveryQueueBatchSize;
|
|
134
|
+
deliveryQueueMaxAttempts;
|
|
135
|
+
deliveryQueueIntervalMs;
|
|
136
|
+
runHeartbeatMs;
|
|
137
|
+
runRecoveryIntervalMs;
|
|
138
|
+
maxModelIterations;
|
|
139
|
+
outputValidationMaxRetries;
|
|
140
|
+
runSemaphore;
|
|
141
|
+
conversationTurnDispatcher;
|
|
142
|
+
memoryEmbeddingProvider;
|
|
143
|
+
memoryEmbeddingsEnabled;
|
|
144
|
+
resourceProjectionPolicy;
|
|
145
|
+
coreToolPolicy;
|
|
146
|
+
telemetry;
|
|
147
|
+
instrumentationLoaded = false;
|
|
148
|
+
providerIngressSecurityLogged = false;
|
|
149
|
+
hostTelemetryProvided;
|
|
150
|
+
hostInstrumentationProvided;
|
|
151
|
+
instrumentationConfig;
|
|
152
|
+
sourceLoader;
|
|
153
|
+
contextPolicyPromise;
|
|
154
|
+
/** Fast local view of durable control intents, refreshed by run heartbeats. */
|
|
155
|
+
runControlIntents = new Map();
|
|
156
|
+
/** Deadline-fired runs (read by shouldStopRun) + their in-flight abort controllers. */
|
|
157
|
+
runDeadlines = new Set();
|
|
158
|
+
runAbortControllers = new Map();
|
|
159
|
+
maxRunDurationMs;
|
|
160
|
+
constructor(options) {
|
|
161
|
+
this.manifest = options.manifest;
|
|
162
|
+
const normalizedState = normalizeRuntimeState(options.state ?? new InMemoryStateAdapter());
|
|
163
|
+
// Events fan out to live streams; terminal outcomes become log lines at
|
|
164
|
+
// this one choke point (logger read lazily — assigned below).
|
|
165
|
+
this.state = withRunEventPublishing(normalizedState.state, this.runEventBus, (runId, event) => logTerminalRunEvent(this.logger, runId, event), (runId, event) => this.dispatchHookEvent(runId, event));
|
|
166
|
+
this.blob = options.blob ?? new LocalBlobAdapter();
|
|
167
|
+
this.sandbox = options.sandbox ?? new LocalSandboxAdapter();
|
|
168
|
+
this.scheduler = options.scheduler ?? schedulerAdapterForKind(this.manifest.gateway.scheduler?.kind);
|
|
169
|
+
this.deliveryMode = options.deliveryMode ?? "send";
|
|
170
|
+
this.toolStubs = options.toolStubs ?? {};
|
|
171
|
+
this.devMode = options.devMode ?? false;
|
|
172
|
+
this.sourceBundle = options.sourceBundle ?? {};
|
|
173
|
+
this.connections = options.connections ?? {};
|
|
174
|
+
this.env = applyEnvAliases(options.env ?? process.env).env;
|
|
175
|
+
this.fetch = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
176
|
+
this.logger = options.logger ??
|
|
177
|
+
createJsonConsoleLogger({ level: normalizeLogLevel(this.env.OPENEVE_LOG_LEVEL) ?? "info" });
|
|
178
|
+
if (normalizedState.degradedFacets.length > 0) {
|
|
179
|
+
this.logger.warn("state.degraded", {
|
|
180
|
+
missingFacets: normalizedState.degradedFacets,
|
|
181
|
+
detail: "optional state facets not configured; using non-durable in-memory fallbacks"
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
this.coreToolPolicy = resolveCoreToolPolicy(options.coreToolPolicy, this.env, this.devMode);
|
|
185
|
+
this.models = options.models;
|
|
186
|
+
this.agentHarnessOverride = options.agentHarness;
|
|
187
|
+
this.modelHarnesses = options.modelHarnesses ?? {};
|
|
188
|
+
this.checkpointEveryIteration = resolveBooleanEnv(this.env.OPENEVE_CHECKPOINT_EVERY_ITERATION, true);
|
|
189
|
+
this.checkpointRetention = resolveCheckpointRetentionPolicy(options.checkpointRetention, this.env);
|
|
190
|
+
this.checkpointBlobStorageEnabled = options.blob !== undefined && this.checkpointRetention.blobThresholdBytes > 0;
|
|
191
|
+
this.telemetry = options.telemetry;
|
|
192
|
+
this.hostTelemetryProvided = options.telemetry !== undefined;
|
|
193
|
+
this.hostInstrumentationProvided = options.instrumentation !== undefined;
|
|
194
|
+
const override = options.instrumentation;
|
|
195
|
+
this.instrumentationConfig = {
|
|
196
|
+
recordInputs: override?.recordInputs ?? false,
|
|
197
|
+
recordOutputs: override?.recordOutputs ?? false,
|
|
198
|
+
functionId: override?.functionId ?? override?.serviceName ?? this.agentName(),
|
|
199
|
+
serviceName: override?.serviceName ?? this.agentName(),
|
|
200
|
+
contentCapture: normalizeCapturePolicy(override?.captureContent)
|
|
201
|
+
};
|
|
202
|
+
this.connectionGrantStore = options.connectionGrantStore ?? new InMemoryConnectionGrantStore();
|
|
203
|
+
this.connectionAuthorizationSessionStore = options.connectionAuthorizationSessionStore ?? new InMemoryConnectionAuthorizationSessionStore();
|
|
204
|
+
this.connectionCallbackBaseUrl = options.connectionCallbackBaseUrl;
|
|
205
|
+
this.skillStore = options.skillStore ?? new InMemorySkillStore();
|
|
206
|
+
this.memoryEmbeddingProvider = options.memoryEmbeddingProvider;
|
|
207
|
+
const memoryEmbeddingsRequested = options.memoryEmbeddingsEnabled ??
|
|
208
|
+
resolveBooleanEnv(this.env.OPENEVE_MEMORY_EMBEDDINGS_ENABLED, Boolean(options.memoryEmbeddingProvider));
|
|
209
|
+
const memoryEmbeddingStoreAvailable = this.state.supportsMemoryEmbeddings?.() ?? true;
|
|
210
|
+
this.memoryEmbeddingsEnabled = memoryEmbeddingsRequested && memoryEmbeddingStoreAvailable;
|
|
211
|
+
if (memoryEmbeddingsRequested && !memoryEmbeddingStoreAvailable) {
|
|
212
|
+
this.logger.warn("memory.embeddings_unavailable", {
|
|
213
|
+
detail: "semantic memory is disabled because the configured state store does not have its optional vector backend enabled"
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
this.memoryStore = options.memoryStore ?? new StateMemoryStore(this.state, this.memoryEmbeddingProvider, this.memoryEmbeddingsEnabled);
|
|
217
|
+
this.scheduleStore = options.scheduleStore ?? new InMemoryScheduleStore();
|
|
218
|
+
this.connectionDefinitionStore = options.connectionDefinitionStore ?? new InMemoryConnectionDefinitionStore();
|
|
219
|
+
this.skillsConfig = resolveSkillsConfig(this.manifest.agent.selfImprovement, this.env);
|
|
220
|
+
this.schedulesConfig = resolveSchedulesConfig(this.manifest.agent.dynamicAutomations ?? this.manifest.agent.dynamicSchedules, this.env);
|
|
221
|
+
this.connectionsConfig = resolveConnectionsConfig(this.manifest.agent.dynamicConnections, this.env);
|
|
222
|
+
this.schedulerEnabled = options.schedulerEnabled;
|
|
223
|
+
this.schedulerTickMs = options.schedulerTickMs ?? 60_000;
|
|
224
|
+
this.scheduleMaxConsecutiveFailures = resolvePositiveIntegerEnv(this.env.OPENEVE_SCHEDULE_MAX_FAILURES, 5);
|
|
225
|
+
this.now = options.now ?? (() => new Date());
|
|
226
|
+
this.sandboxSnapshotPolicy = resolveSandboxSnapshotPolicy(this.manifest, this.env, options.sandboxSnapshotPolicy);
|
|
227
|
+
this.sandboxSyncInline = options.sandboxSyncInline ?? resolveBooleanEnv(this.env.OPENEVE_SANDBOX_SYNC_INLINE, false);
|
|
228
|
+
this.sandboxSyncLeaseMs = options.sandboxSyncLeaseMs ?? resolvePositiveIntegerEnv(this.env.OPENEVE_SANDBOX_SYNC_LEASE_MS, 5 * 60_000);
|
|
229
|
+
this.sandboxSyncBatchSize = options.sandboxSyncBatchSize ?? resolvePositiveIntegerEnv(this.env.OPENEVE_SANDBOX_SYNC_BATCH_SIZE, 10);
|
|
230
|
+
this.sandboxSyncMaxAttempts = options.sandboxSyncMaxAttempts ?? resolvePositiveIntegerEnv(this.env.OPENEVE_SANDBOX_SYNC_MAX_ATTEMPTS, 5);
|
|
231
|
+
this.deliveryQueueLeaseMs = options.deliveryQueueLeaseMs ?? resolvePositiveIntegerEnv(this.env.OPENEVE_DELIVERY_QUEUE_LEASE_MS, 60_000);
|
|
232
|
+
this.toolOutputMaxChars = resolvePositiveIntegerEnv(this.env.OPENEVE_TOOL_OUTPUT_MAX_CHARS, DEFAULT_MODEL_OUTPUT_MAX_CHARS);
|
|
233
|
+
this.toolTimeoutMs = resolveNonNegativeIntegerEnv(this.env.OPENEVE_TOOL_TIMEOUT_MS, 600_000);
|
|
234
|
+
this.deliveryQueueBatchSize = options.deliveryQueueBatchSize ?? resolvePositiveIntegerEnv(this.env.OPENEVE_DELIVERY_QUEUE_BATCH_SIZE, 10);
|
|
235
|
+
this.deliveryQueueMaxAttempts = options.deliveryQueueMaxAttempts ?? resolvePositiveIntegerEnv(this.env.OPENEVE_DELIVERY_QUEUE_MAX_ATTEMPTS, 5);
|
|
236
|
+
this.deliveryQueueIntervalMs = options.deliveryQueueIntervalMs ?? resolvePositiveIntegerEnv(this.env.OPENEVE_DELIVERY_QUEUE_INTERVAL_MS, 15_000);
|
|
237
|
+
this.runHeartbeatMs = options.runHeartbeatMs ?? resolvePositiveIntegerEnv(this.env.OPENEVE_RUN_HEARTBEAT_MS, 30_000);
|
|
238
|
+
this.maxRunDurationMs = options.maxRunDurationMs ?? resolveNonNegativeIntegerEnv(this.env.OPENEVE_MAX_RUN_DURATION_MS, 3_600_000);
|
|
239
|
+
this.runRecoveryIntervalMs = options.runRecoveryIntervalMs ?? resolvePositiveIntegerEnv(this.env.OPENEVE_RUN_RECOVERY_INTERVAL_MS, 60_000);
|
|
240
|
+
this.maxModelIterations = resolvePositiveIntegerEnv(this.env.OPENEVE_MAX_MODEL_ITERATIONS, DEFAULT_MAX_MODEL_ITERATIONS);
|
|
241
|
+
this.outputValidationMaxRetries = resolveNonNegativeIntegerEnv(this.env.OPENEVE_OUTPUT_VALIDATION_MAX_RETRIES, DEFAULT_OUTPUT_VALIDATION_MAX_RETRIES);
|
|
242
|
+
this.runSemaphore = new BoundedSemaphore({
|
|
243
|
+
maxConcurrent: options.maxConcurrentRuns ?? resolvePositiveIntegerEnv(this.env.OPENEVE_MAX_CONCURRENT_RUNS, Infinity),
|
|
244
|
+
maxQueued: options.maxQueuedRuns ?? resolvePositiveIntegerEnv(this.env.OPENEVE_MAX_QUEUED_RUNS, 0)
|
|
245
|
+
});
|
|
246
|
+
this.conversationTurnDispatcher = new ConversationTurnDispatcher({
|
|
247
|
+
state: this.state, logger: this.logger,
|
|
248
|
+
agentScope: this.durableAgentScope(), maxRunDurationMs: this.maxRunDurationMs,
|
|
249
|
+
now: () => this.now(), agentEnabled: () => this.agentEnabled(),
|
|
250
|
+
admitRunOrReject: () => this.admitRunOrReject(),
|
|
251
|
+
runTurn: (turn, admission, onRunCreated) => this.run({
|
|
252
|
+
message: turn.message,
|
|
253
|
+
channel: turn.channel, turn, admission, startChannelTurnEarly: true,
|
|
254
|
+
onRunCreated
|
|
255
|
+
})
|
|
256
|
+
});
|
|
257
|
+
this.resourceProjectionPolicy = resolveResourceProjectionPolicy(options.resourceProjectionPolicy, this.env);
|
|
258
|
+
this.sourceLoader = new AgentSourceModuleLoader({
|
|
259
|
+
manifest: this.manifest,
|
|
260
|
+
sourceBundle: this.sourceBundle,
|
|
261
|
+
...(options.artifactRoot ? { cacheRoot: join(resolve(options.artifactRoot), ".assembly-line", "module-cache") } : {})
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
boot() {
|
|
265
|
+
if (this.manifest.schemaVersion !== OPENEVE_MANIFEST_SCHEMA_VERSION) {
|
|
266
|
+
throw new Error(`Unsupported OpenEve manifest schema ${this.manifest.schemaVersion}.`);
|
|
267
|
+
}
|
|
268
|
+
if (!this.devMode) {
|
|
269
|
+
const missing = this.manifest.preflight.filter((requirement) => requirement.kind === "env" &&
|
|
270
|
+
requirement.required &&
|
|
271
|
+
requirement.name !== "RAILWAY_TOKEN" &&
|
|
272
|
+
![requirement.name, ...(requirement.alternatives ?? [])]
|
|
273
|
+
.some((name) => Boolean(this.env[name]?.trim())));
|
|
274
|
+
if (missing.length > 0) {
|
|
275
|
+
throw new Error(`Missing required runtime bindings: ${missing
|
|
276
|
+
.map((requirement) => [requirement.name, ...(requirement.alternatives ?? [])].join(" or "))
|
|
277
|
+
.join(", ")}`);
|
|
278
|
+
}
|
|
279
|
+
this.validateProviderIngressSecurity();
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
this.logDevProviderIngressSecurity();
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
validateProviderIngressSecurity() {
|
|
286
|
+
const error = providerIngressSecurityError(this.manifest.channels, this.env);
|
|
287
|
+
if (error)
|
|
288
|
+
throw new Error(error);
|
|
289
|
+
}
|
|
290
|
+
debugSwallow(message, fields) {
|
|
291
|
+
return (error) => {
|
|
292
|
+
this.logger.debug(message, { ...fields, error: error instanceof Error ? error.message : String(error) });
|
|
293
|
+
return undefined;
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
warnSwallow(message, fields) {
|
|
297
|
+
return (error) => {
|
|
298
|
+
this.logger.warn(message, { ...fields, error: error instanceof Error ? error.message : String(error) });
|
|
299
|
+
return undefined;
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
async compactCheckpoints(options = {}) {
|
|
303
|
+
if (!this.state.compactCheckpoints)
|
|
304
|
+
return emptyCheckpointRetentionResult(options.dryRun === true);
|
|
305
|
+
return this.state.compactCheckpoints({
|
|
306
|
+
maxActivePerRunName: this.checkpointRetention.maxActivePerRunName,
|
|
307
|
+
activeNames: COMPACTABLE_ACTIVE_CHECKPOINT_NAMES,
|
|
308
|
+
terminalTtlMs: this.checkpointRetention.terminalTtlMs,
|
|
309
|
+
failedRunTtlMs: this.checkpointRetention.failedRunTtlMs,
|
|
310
|
+
scheduledRunTtlMs: this.checkpointRetention.scheduledRunTtlMs,
|
|
311
|
+
now: this.now(),
|
|
312
|
+
...options
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async createCheckpoint(input) {
|
|
316
|
+
const storedData = await this.checkpointDataForStorage(input.runId, input.name, input.data);
|
|
317
|
+
const checkpoint = await this.state.createCheckpoint({ ...input, data: storedData });
|
|
318
|
+
if (COMPACTABLE_ACTIVE_CHECKPOINT_NAMES.includes(input.name)) {
|
|
319
|
+
await this.compactCheckpoints({
|
|
320
|
+
runId: input.runId,
|
|
321
|
+
activeNames: COMPACTABLE_ACTIVE_CHECKPOINT_NAMES,
|
|
322
|
+
terminalTtlMs: undefined,
|
|
323
|
+
failedRunTtlMs: undefined,
|
|
324
|
+
scheduledRunTtlMs: undefined
|
|
325
|
+
}).catch(this.warnSwallow("checkpoint active compaction failed", { runId: input.runId, checkpointName: input.name }));
|
|
326
|
+
}
|
|
327
|
+
return { ...checkpoint, data: input.data };
|
|
328
|
+
}
|
|
329
|
+
async listHydratedCheckpoints(runId) {
|
|
330
|
+
const checkpoints = await this.state.listCheckpoints(runId);
|
|
331
|
+
return Promise.all(checkpoints.map(async (checkpoint) => ({
|
|
332
|
+
...checkpoint,
|
|
333
|
+
data: await this.hydrateCheckpointData(checkpoint.data)
|
|
334
|
+
})));
|
|
335
|
+
}
|
|
336
|
+
async checkpointDataForStorage(runId, name, data) {
|
|
337
|
+
return checkpointDataForBlobStorage({ blob: this.blob, enabled: this.checkpointBlobStorageEnabled, thresholdBytes: this.checkpointRetention.blobThresholdBytes, runId, name, data });
|
|
338
|
+
}
|
|
339
|
+
async hydrateCheckpointData(data) { return hydrateCheckpointDataFromBlob(data, this.blob); }
|
|
340
|
+
logDevProviderIngressSecurity() {
|
|
341
|
+
if (this.providerIngressSecurityLogged)
|
|
342
|
+
return;
|
|
343
|
+
const warnings = providerIngressSecurityWarnings(this.manifest.channels, this.env);
|
|
344
|
+
if (warnings.length === 0)
|
|
345
|
+
return;
|
|
346
|
+
this.providerIngressSecurityLogged = true;
|
|
347
|
+
for (const warning of warnings) {
|
|
348
|
+
this.logger.warn("provider ingress security warning", { warning });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
skillScope() {
|
|
352
|
+
return this.durableAgentScope();
|
|
353
|
+
}
|
|
354
|
+
connectionScope() {
|
|
355
|
+
return this.durableAgentScope();
|
|
356
|
+
}
|
|
357
|
+
durableAgentScope() {
|
|
358
|
+
return durableAgentScopeForManifest(this.manifest);
|
|
359
|
+
}
|
|
360
|
+
usesRevisionScopedDurableState() {
|
|
361
|
+
return this.durableAgentScope() === this.manifest.agentRevision;
|
|
362
|
+
}
|
|
363
|
+
scheduleScopeForRun(run) {
|
|
364
|
+
const userId = typeof run.input.userId === "string" ? run.input.userId : undefined;
|
|
365
|
+
const conversationId = typeof run.input.conversationId === "string" ? run.input.conversationId : undefined;
|
|
366
|
+
return userId ?? conversationId ?? this.manifest.agentRevision;
|
|
367
|
+
}
|
|
368
|
+
/** Seed the durable skill store from compiled manifest skills (idempotent). */
|
|
369
|
+
async ensureSkillsSeeded() {
|
|
370
|
+
if (this.skillsSeeded)
|
|
371
|
+
return;
|
|
372
|
+
await this.migrateLegacySkillScope();
|
|
373
|
+
await seedSkills(this.skillStore, this.skillScope(), this.manifest.skills);
|
|
374
|
+
this.skillsSeeded = true;
|
|
375
|
+
}
|
|
376
|
+
async migrateLegacySkillScope() {
|
|
377
|
+
if (this.skillScopeMigrated)
|
|
378
|
+
return;
|
|
379
|
+
this.skillScopeMigrated = true;
|
|
380
|
+
const scope = this.skillScope();
|
|
381
|
+
const legacyScope = this.manifest.agentRevision;
|
|
382
|
+
if (scope === legacyScope)
|
|
383
|
+
return;
|
|
384
|
+
const current = await this.skillStore.list(scope);
|
|
385
|
+
if (current.length > 0)
|
|
386
|
+
return;
|
|
387
|
+
for (const skill of await this.skillStore.list(legacyScope)) {
|
|
388
|
+
await this.skillStore.put(scope, skill);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
async migrateLegacyConnectionScope() {
|
|
392
|
+
if (this.connectionScopeMigrated)
|
|
393
|
+
return;
|
|
394
|
+
this.connectionScopeMigrated = true;
|
|
395
|
+
const scope = this.connectionScope();
|
|
396
|
+
const legacyScope = this.manifest.agentRevision;
|
|
397
|
+
if (scope === legacyScope)
|
|
398
|
+
return;
|
|
399
|
+
const current = await this.connectionDefinitionStore.list(scope);
|
|
400
|
+
if (current.length > 0)
|
|
401
|
+
return;
|
|
402
|
+
for (const definition of await this.connectionDefinitionStore.list(legacyScope)) {
|
|
403
|
+
await this.connectionDefinitionStore.put(scope, { ...definition, scope });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/** Live skill catalog (durable store, post-seed) for context assembly and inspection. */
|
|
407
|
+
async listSkills() {
|
|
408
|
+
await this.ensureSkillsSeeded();
|
|
409
|
+
return liveSkills(this.skillStore, this.skillScope());
|
|
410
|
+
}
|
|
411
|
+
/** Persist an agent/user authored skill, honoring the write-approval gate. */
|
|
412
|
+
async saveSkill(input) {
|
|
413
|
+
if (!this.skillsConfig.writable) {
|
|
414
|
+
throw new Error("Skill writing is disabled (selfImprovement.writable is false).");
|
|
415
|
+
}
|
|
416
|
+
await this.ensureSkillsSeeded();
|
|
417
|
+
const writeInput = { name: input.name, body: input.body };
|
|
418
|
+
if (input.origin)
|
|
419
|
+
writeInput.origin = input.origin;
|
|
420
|
+
const record = await writeSkill(this.skillStore, this.skillScope(), writeInput, {
|
|
421
|
+
requireApproval: this.skillsConfig.writeApproval
|
|
422
|
+
});
|
|
423
|
+
return { name: record.name, pending: record.pending ?? false };
|
|
424
|
+
}
|
|
425
|
+
async deleteSkill(name) {
|
|
426
|
+
if (!this.skillsConfig.writable) {
|
|
427
|
+
throw new Error("Skill writing is disabled (selfImprovement.writable is false).");
|
|
428
|
+
}
|
|
429
|
+
await this.ensureSkillsSeeded();
|
|
430
|
+
await this.skillStore.delete(this.skillScope(), name);
|
|
431
|
+
}
|
|
432
|
+
async createDynamicSchedule(input) {
|
|
433
|
+
if (!this.schedulesConfig.dynamic) {
|
|
434
|
+
throw new Error("Dynamic automations are disabled (dynamicAutomations.dynamic is false).");
|
|
435
|
+
}
|
|
436
|
+
const trigger = input.trigger ? this.normalizeScheduleTriggerDefinition(input.trigger) : undefined;
|
|
437
|
+
const prompt = stringValue(input.prompt) || stringValue(input.message) || (trigger ? `Run scheduled trigger ${trigger.handler}.` : "");
|
|
438
|
+
if (!prompt)
|
|
439
|
+
throw new Error("Dynamic schedules require prompt or message.");
|
|
440
|
+
const createInput = {
|
|
441
|
+
...input,
|
|
442
|
+
prompt
|
|
443
|
+
};
|
|
444
|
+
if (input.message)
|
|
445
|
+
createInput.message = input.message;
|
|
446
|
+
if (trigger)
|
|
447
|
+
createInput.trigger = trigger;
|
|
448
|
+
return this.scheduleStore.create(createInput);
|
|
449
|
+
}
|
|
450
|
+
async createDynamicAutomation(input) {
|
|
451
|
+
return this.createDynamicSchedule(input);
|
|
452
|
+
}
|
|
453
|
+
async listDynamicSchedules(scope) {
|
|
454
|
+
return this.scheduleStore.list(scope);
|
|
455
|
+
}
|
|
456
|
+
async listDynamicAutomations(scope) {
|
|
457
|
+
return this.listDynamicSchedules(scope);
|
|
458
|
+
}
|
|
459
|
+
async updateDynamicSchedule(scope, id, patch) {
|
|
460
|
+
if (!this.schedulesConfig.dynamic) {
|
|
461
|
+
throw new Error("Dynamic automations are disabled (dynamicAutomations.dynamic is false).");
|
|
462
|
+
}
|
|
463
|
+
const normalized = { ...patch };
|
|
464
|
+
if (Object.prototype.hasOwnProperty.call(patch, "trigger")) {
|
|
465
|
+
const rawTrigger = patch.trigger;
|
|
466
|
+
normalized.trigger = rawTrigger === null ? null : this.normalizeScheduleTriggerDefinition(rawTrigger);
|
|
467
|
+
}
|
|
468
|
+
return this.scheduleStore.update(scope, id, normalized);
|
|
469
|
+
}
|
|
470
|
+
async updateDynamicAutomation(scope, id, patch) {
|
|
471
|
+
return this.updateDynamicSchedule(scope, id, patch);
|
|
472
|
+
}
|
|
473
|
+
async deleteDynamicSchedule(scope, id) {
|
|
474
|
+
return this.scheduleStore.delete(scope, id);
|
|
475
|
+
}
|
|
476
|
+
async deleteDynamicAutomation(scope, id) {
|
|
477
|
+
return this.deleteDynamicSchedule(scope, id);
|
|
478
|
+
}
|
|
479
|
+
/** Persist a runtime-provided connection definition (gated). Credentials route to the grant store. */
|
|
480
|
+
async saveConnectionDefinition(input) {
|
|
481
|
+
if (!this.connectionsConfig.dynamic) {
|
|
482
|
+
throw new Error("Dynamic connections are disabled (dynamicConnections.dynamic is false).");
|
|
483
|
+
}
|
|
484
|
+
if (input.protocol === "mcp" && (input.definition.transport === "stdio"
|
|
485
|
+
|| "command" in input.definition
|
|
486
|
+
|| "args" in input.definition
|
|
487
|
+
|| "cwd" in input.definition
|
|
488
|
+
|| "env" in input.definition)) {
|
|
489
|
+
throw new Error("Dynamic MCP connections are URL-only and cannot launch host processes.");
|
|
490
|
+
}
|
|
491
|
+
const url = typeof input.definition.url === "string" ? input.definition.url : undefined;
|
|
492
|
+
if (input.protocol === "mcp" && !url) {
|
|
493
|
+
throw new Error("Dynamic MCP connections must provide an HTTP url.");
|
|
494
|
+
}
|
|
495
|
+
if (url && !isHostAllowed(url, this.connectionsConfig.allowedHosts)) {
|
|
496
|
+
throw new Error(`Connection host is not allowlisted: ${url}`);
|
|
497
|
+
}
|
|
498
|
+
await this.migrateLegacyConnectionScope();
|
|
499
|
+
const scope = input.scope ?? this.connectionScope();
|
|
500
|
+
const now = timestamp();
|
|
501
|
+
await this.connectionDefinitionStore.put(scope, {
|
|
502
|
+
name: input.name,
|
|
503
|
+
scope,
|
|
504
|
+
protocol: input.protocol,
|
|
505
|
+
description: input.description,
|
|
506
|
+
definition: input.definition,
|
|
507
|
+
origin: "agent",
|
|
508
|
+
createdAt: now,
|
|
509
|
+
updatedAt: now
|
|
510
|
+
});
|
|
511
|
+
if (input.grant) {
|
|
512
|
+
const principal = input.grant.principal ?? { type: "app" };
|
|
513
|
+
await this.connectionGrantStore.saveGrant({
|
|
514
|
+
connectionName: input.name,
|
|
515
|
+
principalKey: input.grant.principalKey ?? connectionPrincipalKeyForGrant(principal),
|
|
516
|
+
principal,
|
|
517
|
+
token: input.grant.token,
|
|
518
|
+
createdAt: now,
|
|
519
|
+
updatedAt: now
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
this.dynamicConnectionsCache = undefined;
|
|
523
|
+
return { name: input.name };
|
|
524
|
+
}
|
|
525
|
+
async listConnectionDefinitions(scope) {
|
|
526
|
+
await this.migrateLegacyConnectionScope();
|
|
527
|
+
const stored = await this.connectionDefinitionStore.list(scope ?? this.connectionScope());
|
|
528
|
+
return stored.map((definition) => ({
|
|
529
|
+
name: definition.name,
|
|
530
|
+
protocol: definition.protocol,
|
|
531
|
+
description: definition.description,
|
|
532
|
+
origin: definition.origin
|
|
533
|
+
}));
|
|
534
|
+
}
|
|
535
|
+
async deleteConnectionDefinition(name, scope) {
|
|
536
|
+
await this.migrateLegacyConnectionScope();
|
|
537
|
+
await this.connectionDefinitionStore.delete(scope ?? this.connectionScope(), name);
|
|
538
|
+
this.dynamicConnectionsCache = undefined;
|
|
539
|
+
}
|
|
540
|
+
async syncMemoryFromSandbox(run, sandboxSession, tombstones) {
|
|
541
|
+
const scope = this.memoryScopeForRun(run);
|
|
542
|
+
const deleted = [];
|
|
543
|
+
const tombstonedPaths = new Set(tombstones
|
|
544
|
+
.map((tombstone) => tombstone.path)
|
|
545
|
+
.filter((path) => path.startsWith("/memory/")));
|
|
546
|
+
for (const path of tombstonedPaths) {
|
|
547
|
+
await this.state.deleteMemoryDocument(scope, path);
|
|
548
|
+
deleted.push(path);
|
|
549
|
+
}
|
|
550
|
+
let files;
|
|
551
|
+
try {
|
|
552
|
+
files = await scanSandboxFiles(sandboxSession, "/memory");
|
|
553
|
+
}
|
|
554
|
+
catch {
|
|
555
|
+
return { written: [], deleted };
|
|
556
|
+
}
|
|
557
|
+
const written = [];
|
|
558
|
+
for (const file of files) {
|
|
559
|
+
const path = memoryPathFromSandboxRelativePath(file.relativePath);
|
|
560
|
+
if (!path || tombstonedPaths.has(path))
|
|
561
|
+
continue;
|
|
562
|
+
const content = sandboxFileContentsToUtf8(file.contents);
|
|
563
|
+
const current = await this.memoryStore.read(scope, { path });
|
|
564
|
+
if (current && memoryBodyText(current) === content)
|
|
565
|
+
continue;
|
|
566
|
+
await this.memoryStore.write(scope, {
|
|
567
|
+
path,
|
|
568
|
+
content,
|
|
569
|
+
mode: "replace",
|
|
570
|
+
metadata: {
|
|
571
|
+
tags: ["sandbox"],
|
|
572
|
+
sourceRefs: [`sandbox:${run.id}`]
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
written.push(path);
|
|
576
|
+
}
|
|
577
|
+
if (written.length > 0 || deleted.length > 0) {
|
|
578
|
+
await this.state.appendEvent(run.id, "memory.documents_synced", {
|
|
579
|
+
written,
|
|
580
|
+
deleted
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
return { written, deleted };
|
|
584
|
+
}
|
|
585
|
+
/** Reconcile skill files the agent explicitly edited/deleted under `/skills`. */
|
|
586
|
+
async syncSkillsFromSandbox(run, sandboxSession, tombstones) {
|
|
587
|
+
let files;
|
|
588
|
+
try {
|
|
589
|
+
files = await scanSandboxFiles(sandboxSession, "/skills");
|
|
590
|
+
}
|
|
591
|
+
catch {
|
|
592
|
+
files = [];
|
|
593
|
+
}
|
|
594
|
+
const skillScope = this.skillScope();
|
|
595
|
+
const before = await this.skillStore.list(skillScope);
|
|
596
|
+
const beforeByName = new Map(before.map((skill) => [skill.name, skill]));
|
|
597
|
+
const deletedSkillNames = new Set(tombstones
|
|
598
|
+
.map((tombstone) => skillNameFromSkillPath(tombstone.path))
|
|
599
|
+
.filter((name) => Boolean(name)));
|
|
600
|
+
const sandboxSkills = [];
|
|
601
|
+
const invalid = [];
|
|
602
|
+
for (const file of files) {
|
|
603
|
+
const name = skillNameFromSandboxRelativePath(file.relativePath);
|
|
604
|
+
if (!name) {
|
|
605
|
+
if (file.relativePath.endsWith("SKILL.md"))
|
|
606
|
+
invalid.push(file.relativePath);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
const body = sandboxFileContentsToUtf8(file.contents);
|
|
610
|
+
if (!isValidSandboxSkillBody(body)) {
|
|
611
|
+
invalid.push(`/skills/${file.relativePath}`);
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
sandboxSkills.push({ name, body });
|
|
615
|
+
}
|
|
616
|
+
const changed = sandboxSkills.filter((skill) => {
|
|
617
|
+
if (deletedSkillNames.has(skill.name))
|
|
618
|
+
return false;
|
|
619
|
+
return beforeByName.get(skill.name)?.bodySha256 !== sha256Text(skill.body);
|
|
620
|
+
});
|
|
621
|
+
if (!this.skillsConfig.writable) {
|
|
622
|
+
if (changed.length > 0 || deletedSkillNames.size > 0 || invalid.length > 0) {
|
|
623
|
+
throw new Error("Sandbox skill writes are blocked because self-improvement is disabled.");
|
|
624
|
+
}
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
if (invalid.length > 0) {
|
|
628
|
+
throw new Error(`Invalid sandbox skill file(s): ${invalid.join(", ")}`);
|
|
629
|
+
}
|
|
630
|
+
const created = [];
|
|
631
|
+
const updated = [];
|
|
632
|
+
const deleted = [];
|
|
633
|
+
for (const name of deletedSkillNames) {
|
|
634
|
+
if (!beforeByName.has(name))
|
|
635
|
+
continue;
|
|
636
|
+
await this.skillStore.delete(skillScope, name);
|
|
637
|
+
deleted.push(name);
|
|
638
|
+
}
|
|
639
|
+
for (const skill of changed) {
|
|
640
|
+
const existing = beforeByName.get(skill.name);
|
|
641
|
+
await writeSkill(this.skillStore, skillScope, {
|
|
642
|
+
name: skill.name,
|
|
643
|
+
body: skill.body,
|
|
644
|
+
origin: "agent"
|
|
645
|
+
}, {
|
|
646
|
+
requireApproval: this.skillsConfig.writeApproval
|
|
647
|
+
});
|
|
648
|
+
if (existing)
|
|
649
|
+
updated.push(skill.name);
|
|
650
|
+
else
|
|
651
|
+
created.push(skill.name);
|
|
652
|
+
}
|
|
653
|
+
if (created.length || updated.length || deleted.length) {
|
|
654
|
+
await this.state.appendEvent(run.id, "skill.synced", {
|
|
655
|
+
created,
|
|
656
|
+
updated,
|
|
657
|
+
deleted,
|
|
658
|
+
pending: this.skillsConfig.writeApproval
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
createSandboxHandle(getRun, setRun, getBundle) {
|
|
663
|
+
const runtime = this;
|
|
664
|
+
let sandboxSession;
|
|
665
|
+
let acquiring;
|
|
666
|
+
const acquire = async () => {
|
|
667
|
+
const run = getRun();
|
|
668
|
+
sandboxSession = await runtime.acquireSandboxForRun(run);
|
|
669
|
+
const updatedRun = await runtime.state.updateRun(run.id, { sandboxId: sandboxSession.id });
|
|
670
|
+
setRun(updatedRun);
|
|
671
|
+
await runtime.state.appendEvent(run.id, "sandbox.acquired", { sandboxId: sandboxSession.id, root: sandboxSession.root });
|
|
672
|
+
await runtime.createCheckpoint({ runId: run.id, name: "sandbox.acquired", data: { sandboxId: sandboxSession.id } });
|
|
673
|
+
await hydrateSandboxFilesystem(sandboxSession, getBundle(), {
|
|
674
|
+
fullHydration: runtime.legacyFullSandboxHydration(),
|
|
675
|
+
blob: runtime.blob
|
|
676
|
+
});
|
|
677
|
+
await runtime.state.appendEvent(run.id, "filesystem.hydrated", {
|
|
678
|
+
memory: "/memory",
|
|
679
|
+
history: "/history",
|
|
680
|
+
files: "/files",
|
|
681
|
+
workspace: "/workspace",
|
|
682
|
+
mode: runtime.legacyFullSandboxHydration() ? "full" : "minimal"
|
|
683
|
+
});
|
|
684
|
+
await runtime.createCheckpoint({
|
|
685
|
+
runId: run.id,
|
|
686
|
+
name: "filesystem.hydrated",
|
|
687
|
+
data: {
|
|
688
|
+
memory: "/memory",
|
|
689
|
+
history: "/history",
|
|
690
|
+
files: "/files",
|
|
691
|
+
workspace: "/workspace",
|
|
692
|
+
mode: runtime.legacyFullSandboxHydration() ? "full" : "minimal"
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
await materializeConnectionCredentialsIntoSandbox(run, runtime.createConnectionRegistryForRun(run, "local"), sandboxSession, (eventType, payload) => runtime.state.appendEvent(run.id, eventType, payload));
|
|
696
|
+
return sandboxSession;
|
|
697
|
+
};
|
|
698
|
+
return {
|
|
699
|
+
current() {
|
|
700
|
+
return sandboxSession;
|
|
701
|
+
},
|
|
702
|
+
async get() {
|
|
703
|
+
if (sandboxSession)
|
|
704
|
+
return sandboxSession;
|
|
705
|
+
// Memoize the in-flight acquisition: parallel tool calls must share
|
|
706
|
+
// one sandbox session instead of racing to create two.
|
|
707
|
+
acquiring ??= acquire().catch((error) => {
|
|
708
|
+
acquiring = undefined;
|
|
709
|
+
throw error;
|
|
710
|
+
});
|
|
711
|
+
return acquiring;
|
|
712
|
+
},
|
|
713
|
+
async getWrapped() {
|
|
714
|
+
const run = getRun();
|
|
715
|
+
return runtime.wrapSandbox(run.id, await this.get());
|
|
716
|
+
},
|
|
717
|
+
async dispose() {
|
|
718
|
+
if (!sandboxSession)
|
|
719
|
+
return;
|
|
720
|
+
await runtime.disposeSandboxSession(getRun().id, sandboxSession);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
sandboxSessionKey(run) {
|
|
725
|
+
return sandboxSessionKeyForRun(this.durableAgentScope(), run);
|
|
726
|
+
}
|
|
727
|
+
async acquireSandboxForRun(run) {
|
|
728
|
+
const sessionKey = this.sandboxSessionKey(run);
|
|
729
|
+
const provider = this.sandbox.provider ?? "sandbox";
|
|
730
|
+
const existing = await this.state.getSandboxSession(sessionKey);
|
|
731
|
+
const reconnectManifest = existing?.manifest ?? {};
|
|
732
|
+
const reconnectCompatible = hasCurrentSandboxFilesystemContract(reconnectManifest);
|
|
733
|
+
const reconnectInput = {
|
|
734
|
+
runId: run.id,
|
|
735
|
+
sandboxId: existing?.sandboxId ?? "",
|
|
736
|
+
sessionKey,
|
|
737
|
+
manifest: reconnectManifest
|
|
738
|
+
};
|
|
739
|
+
const root = stringValue(reconnectManifest.sandboxRoot);
|
|
740
|
+
if (root)
|
|
741
|
+
reconnectInput.root = root;
|
|
742
|
+
if (existing?.sandboxId && reconnectCompatible) {
|
|
743
|
+
const connected = await this.sandbox.connect?.(reconnectInput)
|
|
744
|
+
.catch(this.debugSwallow("sandbox connect probe failed", { runId: run.id, sessionKey }));
|
|
745
|
+
if (connected) {
|
|
746
|
+
await this.upsertSandboxSessionForRun(run, sessionKey, provider, connected, existing.dirty, existing.syncJobId, {
|
|
747
|
+
...existing.manifest,
|
|
748
|
+
sandboxRoot: connected.root,
|
|
749
|
+
...sandboxFilesystemContractMetadata(connected.provider === "local" ? "emulated" : "physical")
|
|
750
|
+
}, "live");
|
|
751
|
+
await this.state.appendEvent(run.id, "sandbox.reused", { sandboxId: connected.id, sessionKey, mode: "connect" });
|
|
752
|
+
return connected;
|
|
753
|
+
}
|
|
754
|
+
const woken = await this.sandbox.wake?.(reconnectInput)
|
|
755
|
+
.catch(this.debugSwallow("sandbox wake probe failed", { runId: run.id, sessionKey }));
|
|
756
|
+
if (woken) {
|
|
757
|
+
await this.upsertSandboxSessionForRun(run, sessionKey, provider, woken, existing.dirty, existing.syncJobId, {
|
|
758
|
+
...existing.manifest,
|
|
759
|
+
sandboxRoot: woken.root,
|
|
760
|
+
...sandboxFilesystemContractMetadata(woken.provider === "local" ? "emulated" : "physical")
|
|
761
|
+
}, "live");
|
|
762
|
+
await this.state.appendEvent(run.id, "sandbox.reused", { sandboxId: woken.id, sessionKey, mode: "wake" });
|
|
763
|
+
return woken;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
const lookup = (!existing || reconnectCompatible) ? await this.sandbox.lookup?.({
|
|
767
|
+
sessionKey,
|
|
768
|
+
runId: run.id,
|
|
769
|
+
agentRevision: run.agentRevision,
|
|
770
|
+
manifest: {
|
|
771
|
+
...reconnectManifest,
|
|
772
|
+
...sandboxFilesystemContractMetadata(this.sandbox.provider === "local" ? "emulated" : "physical")
|
|
773
|
+
}
|
|
774
|
+
}).catch(this.debugSwallow("sandbox lookup probe failed", { runId: run.id, sessionKey })) : undefined;
|
|
775
|
+
if (lookup) {
|
|
776
|
+
const lookupInput = {
|
|
777
|
+
runId: run.id,
|
|
778
|
+
sandboxId: lookup.sandboxId,
|
|
779
|
+
sessionKey,
|
|
780
|
+
manifest: lookup.manifest ?? reconnectManifest
|
|
781
|
+
};
|
|
782
|
+
if (lookup.root)
|
|
783
|
+
lookupInput.root = lookup.root;
|
|
784
|
+
const connected = await this.sandbox.connect?.(lookupInput)
|
|
785
|
+
.catch(this.debugSwallow("sandbox connect probe failed", { runId: run.id, sessionKey })) ??
|
|
786
|
+
await this.sandbox.wake?.(lookupInput)
|
|
787
|
+
.catch(this.debugSwallow("sandbox wake probe failed", { runId: run.id, sessionKey }));
|
|
788
|
+
if (connected) {
|
|
789
|
+
await this.upsertSandboxSessionForRun(run, sessionKey, provider, connected, existing?.dirty ?? false, existing?.syncJobId, {
|
|
790
|
+
...(lookup.manifest ?? existing?.manifest ?? {}),
|
|
791
|
+
sandboxRoot: connected.root,
|
|
792
|
+
...sandboxFilesystemContractMetadata(connected.provider === "local" ? "emulated" : "physical")
|
|
793
|
+
}, "live");
|
|
794
|
+
await this.state.appendEvent(run.id, "sandbox.reused", { sandboxId: connected.id, sessionKey, mode: lookup.state ?? "lookup" });
|
|
795
|
+
return connected;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
const createInput = {
|
|
799
|
+
sessionKey,
|
|
800
|
+
metadata: {
|
|
801
|
+
sessionKey,
|
|
802
|
+
runId: run.id,
|
|
803
|
+
agentRevision: run.agentRevision,
|
|
804
|
+
...sandboxFilesystemContractMetadata(this.sandbox.provider === "local" ? "emulated" : "physical")
|
|
805
|
+
}
|
|
806
|
+
};
|
|
807
|
+
if (existing?.snapshotId && reconnectCompatible)
|
|
808
|
+
createInput.snapshotId = existing.snapshotId;
|
|
809
|
+
const created = this.sandbox.create
|
|
810
|
+
? await this.sandbox.create(run, createInput)
|
|
811
|
+
: await this.sandbox.acquire(run);
|
|
812
|
+
await this.upsertSandboxSessionForRun(run, sessionKey, provider, created, existing?.dirty ?? false, existing?.syncJobId, {
|
|
813
|
+
...(existing?.manifest ?? {}),
|
|
814
|
+
sandboxRoot: created.root,
|
|
815
|
+
...sandboxFilesystemContractMetadata(created.provider === "local" ? "emulated" : "physical")
|
|
816
|
+
}, existing?.dirty ? "dirty" : "live");
|
|
817
|
+
await this.state.appendEvent(run.id, "sandbox.created", { sandboxId: created.id, sessionKey });
|
|
818
|
+
return created;
|
|
819
|
+
}
|
|
820
|
+
async upsertSandboxSessionForRun(run, sessionKey, provider, session, dirty, syncJobId, manifest, state) {
|
|
821
|
+
return this.state.upsertSandboxSession({
|
|
822
|
+
sessionKey,
|
|
823
|
+
provider: session.provider ?? provider,
|
|
824
|
+
sandboxId: session.id,
|
|
825
|
+
runId: run.id,
|
|
826
|
+
state: dirty ? "dirty" : state,
|
|
827
|
+
dirty,
|
|
828
|
+
lastSeenAt: timestamp(),
|
|
829
|
+
...(syncJobId ? { syncJobId } : {}),
|
|
830
|
+
manifest
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
legacyFullSandboxHydration() {
|
|
834
|
+
return this.env.OPENEVE_LEGACY_FULL_SANDBOX_HYDRATION === "1" ||
|
|
835
|
+
this.env.OPENEVE_LEGACY_FULL_SANDBOX_HYDRATION === "true";
|
|
836
|
+
}
|
|
837
|
+
async ensureDynamicConnections() {
|
|
838
|
+
if (!this.connectionsConfig.dynamic) {
|
|
839
|
+
this.dynamicConnectionsCache = { compiled: [], defs: new Map() };
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
if (this.dynamicConnectionsCache)
|
|
843
|
+
return;
|
|
844
|
+
await this.migrateLegacyConnectionScope();
|
|
845
|
+
const stored = await this.connectionDefinitionStore.list(this.connectionScope());
|
|
846
|
+
const compiled = [];
|
|
847
|
+
const defs = new Map();
|
|
848
|
+
for (const definition of stored) {
|
|
849
|
+
compiled.push(compiledConnectionFromStored(definition));
|
|
850
|
+
defs.set(definition.name, definition.definition);
|
|
851
|
+
}
|
|
852
|
+
this.dynamicConnectionsCache = { compiled, defs };
|
|
853
|
+
}
|
|
854
|
+
mergedConnections() {
|
|
855
|
+
const dynamic = this.dynamicConnectionsCache?.compiled ?? [];
|
|
856
|
+
if (dynamic.length === 0)
|
|
857
|
+
return this.manifest.connections;
|
|
858
|
+
const byName = new Map(this.manifest.connections.map((connection) => [connection.name, connection]));
|
|
859
|
+
for (const connection of dynamic)
|
|
860
|
+
byName.set(connection.name, connection);
|
|
861
|
+
return [...byName.values()];
|
|
862
|
+
}
|
|
863
|
+
/** True when a brand-new run would be admitted (or queued) instead of rejected. */
|
|
864
|
+
hasRunCapacity() {
|
|
865
|
+
return this.runSemaphore.hasCapacity();
|
|
866
|
+
}
|
|
867
|
+
/** Resolves once no runs (new or resumed) are executing or queued. Used by graceful shutdown. */
|
|
868
|
+
onIdle() {
|
|
869
|
+
return this.runSemaphore.onIdle();
|
|
870
|
+
}
|
|
871
|
+
/** Claim a new-run slot, returning the capacity error instead of throwing. */
|
|
872
|
+
admitRunOrReject() {
|
|
873
|
+
try {
|
|
874
|
+
return this.runSemaphore.admit();
|
|
875
|
+
}
|
|
876
|
+
catch (error) {
|
|
877
|
+
if (error instanceof RunCapacityError)
|
|
878
|
+
return error;
|
|
879
|
+
throw error;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
/** Count a resume/continuation entry point toward `onIdle()` without consuming run capacity. */
|
|
883
|
+
async withRunAdmission(work) {
|
|
884
|
+
const admission = this.runSemaphore.enter();
|
|
885
|
+
try {
|
|
886
|
+
return await work();
|
|
887
|
+
}
|
|
888
|
+
finally {
|
|
889
|
+
admission.release();
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* Admission choke point: brand-new runs claim a `maxConcurrentRuns` slot
|
|
894
|
+
* (throwing `RunCapacityError` when saturated); resumes and scheduler
|
|
895
|
+
* continuations (`existingRun`) bypass the limit — queueing a resume behind
|
|
896
|
+
* the run it unblocks would deadlock — but still count toward `onIdle()`.
|
|
897
|
+
*/
|
|
898
|
+
async run(options) {
|
|
899
|
+
const admission = options.admission ??
|
|
900
|
+
(options.existingRun ? this.runSemaphore.enter() : this.runSemaphore.admit());
|
|
901
|
+
let earlyChannelTurn;
|
|
902
|
+
try {
|
|
903
|
+
await admission.ready;
|
|
904
|
+
if (options.startChannelTurnEarly) {
|
|
905
|
+
const channel = options.turn?.channel ?? options.channel ?? "local";
|
|
906
|
+
earlyChannelTurn = this.beginChannelTurn(channel, options.turn);
|
|
907
|
+
}
|
|
908
|
+
return await this.executeRun(options, earlyChannelTurn);
|
|
909
|
+
}
|
|
910
|
+
catch (error) {
|
|
911
|
+
if (earlyChannelTurn) {
|
|
912
|
+
const channel = options.turn?.channel ?? options.channel ?? "local";
|
|
913
|
+
await this.stopUnclaimedChannelTurn(await earlyChannelTurn, channel);
|
|
914
|
+
}
|
|
915
|
+
throw error;
|
|
916
|
+
}
|
|
917
|
+
finally {
|
|
918
|
+
admission.release();
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
async executeRun(options, earlyChannelTurn) {
|
|
922
|
+
this.boot();
|
|
923
|
+
await this.initializeInstrumentation();
|
|
924
|
+
await this.ensureSkillsSeeded();
|
|
925
|
+
await this.ensureDynamicConnections();
|
|
926
|
+
const spanStartedAt = timestamp();
|
|
927
|
+
const channel = options.turn?.channel ?? options.channel ?? "local";
|
|
928
|
+
const channelDefinition = this.manifest.channels.find((candidate) => candidate.name === channel);
|
|
929
|
+
const targetModel = options.target?.type === "agent" ? options.target.model : undefined;
|
|
930
|
+
const model = options.model ?? options.turn?.model ?? targetModel;
|
|
931
|
+
const runInput = {
|
|
932
|
+
message: options.message,
|
|
933
|
+
model: model ?? this.manifest.agent.model,
|
|
934
|
+
channel,
|
|
935
|
+
eventId: options.turn?.eventId ?? options.eventId ?? null,
|
|
936
|
+
conversationId: options.turn?.conversationId ?? options.conversationId ?? null,
|
|
937
|
+
userId: options.turn?.userId ?? options.userId ?? null,
|
|
938
|
+
projectId: options.projectId ?? options.existingRun?.input.projectId ?? null,
|
|
939
|
+
delivery: options.turn?.delivery ?? options.delivery ?? null,
|
|
940
|
+
metadata: options.metadata ?? options.turn?.metadata ?? {},
|
|
941
|
+
...(options.eval !== undefined ? { eval: validateEvalRunOptions(options.eval) } : {})
|
|
942
|
+
};
|
|
943
|
+
let run = options.existingRun
|
|
944
|
+
? await this.state.updateRun(options.existingRun.id, {
|
|
945
|
+
input: {
|
|
946
|
+
...options.existingRun.input,
|
|
947
|
+
...runInput
|
|
948
|
+
}
|
|
949
|
+
})
|
|
950
|
+
: await this.state.createRun({
|
|
951
|
+
agentRevision: this.manifest.agentRevision,
|
|
952
|
+
status: "created",
|
|
953
|
+
input: runInput
|
|
954
|
+
});
|
|
955
|
+
try {
|
|
956
|
+
await options.onRunCreated?.(run);
|
|
957
|
+
}
|
|
958
|
+
catch (error) {
|
|
959
|
+
this.logger.warn("onRunCreated hook failed", { runId: run.id, error: error instanceof Error ? error.message : String(error) });
|
|
960
|
+
}
|
|
961
|
+
await this.state.appendEvent(run.id, "run.accepted", { agentRevision: this.manifest.agentRevision, model: model ?? this.manifest.agent.model });
|
|
962
|
+
if (this.usesRevisionScopedDurableState() && (this.skillsConfig.writable || this.connectionsConfig.dynamic)) {
|
|
963
|
+
await this.state.appendEvent(run.id, "agent.scope_fallback", {
|
|
964
|
+
reason: "missing_agent_id",
|
|
965
|
+
scope: this.manifest.agentRevision,
|
|
966
|
+
message: "Durable learned state is scoped to agentRevision because agent.id is not configured."
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
run = await this.state.updateRun(run.id, { status: "running" });
|
|
970
|
+
const heartbeat = this.startRunHeartbeat(run.id);
|
|
971
|
+
const channelTurnStart = earlyChannelTurn
|
|
972
|
+
? await earlyChannelTurn
|
|
973
|
+
: await this.beginChannelTurn(channel, options.turn);
|
|
974
|
+
await this.recordChannelTurnStart(channelTurnStart, run, channel);
|
|
975
|
+
channelTurnStart.claimed = true;
|
|
976
|
+
const channelLifecycle = channelTurnStart.lifecycle;
|
|
977
|
+
let channelLifecycleStopped = false;
|
|
978
|
+
const trustedProvider = options.trustedAttachmentProvider ?? trustedAttachmentProviderForTurn(channelDefinition, options.turn);
|
|
979
|
+
const stopChannelLifecycle = async () => {
|
|
980
|
+
if (channelLifecycleStopped)
|
|
981
|
+
return;
|
|
982
|
+
channelLifecycleStopped = true;
|
|
983
|
+
await this.stopChannelTurn(channelLifecycle, run, channel);
|
|
984
|
+
};
|
|
985
|
+
try {
|
|
986
|
+
const resolveAttachment = await this.channelAttachmentResolver(channelDefinition, trustedProvider);
|
|
987
|
+
const attachments = await materializeTurnAttachments({
|
|
988
|
+
run,
|
|
989
|
+
channel,
|
|
990
|
+
attachments: options.attachments ?? options.turn?.attachments ?? [],
|
|
991
|
+
...(trustedProvider ? { trustedProvider } : {}),
|
|
992
|
+
...(resolveAttachment ? { resolveAttachment } : {}),
|
|
993
|
+
env: this.env,
|
|
994
|
+
fetch: this.fetch,
|
|
995
|
+
blob: this.blob,
|
|
996
|
+
state: this.state
|
|
997
|
+
});
|
|
998
|
+
const hydratedOptions = { ...options, attachments };
|
|
999
|
+
if (options.turn)
|
|
1000
|
+
hydratedOptions.turn = { ...options.turn, attachments };
|
|
1001
|
+
const conversation = await this.prepareConversation(run, hydratedOptions, channel);
|
|
1002
|
+
const augmentation = hydratedOptions.turn
|
|
1003
|
+
? await this.augmentChannelContext(channel, hydratedOptions.turn, run)
|
|
1004
|
+
: undefined;
|
|
1005
|
+
const recentHistory = hydratedOptions.recentHistory ??
|
|
1006
|
+
hydratedOptions.turn?.recentHistory ??
|
|
1007
|
+
augmentation?.recentHistory ??
|
|
1008
|
+
(conversation ? await this.recentHistory(conversation.id) : []);
|
|
1009
|
+
const contextInput = {
|
|
1010
|
+
message: hydratedOptions.message,
|
|
1011
|
+
channel,
|
|
1012
|
+
recentHistory,
|
|
1013
|
+
attachments,
|
|
1014
|
+
run
|
|
1015
|
+
};
|
|
1016
|
+
if (augmentation?.channelContext)
|
|
1017
|
+
contextInput.channelContext = augmentation.channelContext;
|
|
1018
|
+
if (hydratedOptions.promptContext)
|
|
1019
|
+
contextInput.promptContext = hydratedOptions.promptContext;
|
|
1020
|
+
if (hydratedOptions.target)
|
|
1021
|
+
contextInput.target = hydratedOptions.target;
|
|
1022
|
+
const bundle = await this.buildContextBundle(contextInput);
|
|
1023
|
+
const contextBlob = await this.blob.put(`context/${run.id}.json`, JSON.stringify(bundle, null, 2), "application/json");
|
|
1024
|
+
run = await this.state.updateRun(run.id, { contextBundleId: contextBlob.id });
|
|
1025
|
+
await this.state.appendEvent(run.id, "context.bundle_built", { contextBundleId: contextBlob.id });
|
|
1026
|
+
await this.createCheckpoint({
|
|
1027
|
+
runId: run.id,
|
|
1028
|
+
name: "context.bundle_built",
|
|
1029
|
+
data: { contextBundleId: contextBlob.id }
|
|
1030
|
+
});
|
|
1031
|
+
const missingConnections = this.missingRequiredConnections();
|
|
1032
|
+
if (missingConnections.length > 0) {
|
|
1033
|
+
const waitingRun = await this.state.updateRun(run.id, { status: "waiting_for_connection" });
|
|
1034
|
+
await this.state.appendEvent(run.id, "connection.required", {
|
|
1035
|
+
missingConnections,
|
|
1036
|
+
recoverable: true
|
|
1037
|
+
});
|
|
1038
|
+
await this.emitSpan("ai.assembly-line.turn", spanStartedAt, this.runSpanAttributes(waitingRun, {
|
|
1039
|
+
status: "waiting_for_connection"
|
|
1040
|
+
}), {
|
|
1041
|
+
spanId: this.turnSpanId(waitingRun.id),
|
|
1042
|
+
status: "ok"
|
|
1043
|
+
});
|
|
1044
|
+
await this.emitSpan("assembly-line.run", spanStartedAt, {
|
|
1045
|
+
runId: run.id,
|
|
1046
|
+
status: "waiting_for_connection",
|
|
1047
|
+
agentRevision: this.manifest.agentRevision
|
|
1048
|
+
});
|
|
1049
|
+
return this.result(waitingRun, `Connection required: ${missingConnections.join(", ")}`, false, false, true);
|
|
1050
|
+
}
|
|
1051
|
+
const resolution = await this.resolveRunCapabilities(run, hydratedOptions, conversation?.id);
|
|
1052
|
+
const sandboxHandle = this.createSandboxHandle(() => run, (nextRun) => {
|
|
1053
|
+
run = nextRun;
|
|
1054
|
+
}, () => bundle);
|
|
1055
|
+
await this.state.appendEvent(run.id, "harness.started", { harness: this.manifest.gateway.runtime?.kind ?? "node" });
|
|
1056
|
+
const baseInstructions = await this.instructionsForRunTarget(run, hydratedOptions.target, bundle.instructions);
|
|
1057
|
+
const targetInstructions = resolution?.instructions
|
|
1058
|
+
? `${baseInstructions}\n\n${resolution.instructions}`
|
|
1059
|
+
: baseInstructions;
|
|
1060
|
+
let response = options.message;
|
|
1061
|
+
let structuredOutput;
|
|
1062
|
+
const tool = this.selectTool(hydratedOptions);
|
|
1063
|
+
if (tool) {
|
|
1064
|
+
const modelSpanStartedAt = timestamp();
|
|
1065
|
+
await this.state.appendEvent(run.id, "model.request_started", { model: model ?? this.manifest.agent.model, forcedTool: tool.name });
|
|
1066
|
+
await this.state.appendEvent(run.id, "model.response_completed", { model: model ?? this.manifest.agent.model, simulated: true });
|
|
1067
|
+
await this.emitSpan("ai.streamText", modelSpanStartedAt, this.runSpanAttributes(run, {
|
|
1068
|
+
model: model ?? this.manifest.agent.model,
|
|
1069
|
+
stepIndex: 0,
|
|
1070
|
+
forcedTool: tool.name,
|
|
1071
|
+
simulated: true,
|
|
1072
|
+
status: "completed"
|
|
1073
|
+
}), {
|
|
1074
|
+
parentSpanId: this.turnSpanId(run.id),
|
|
1075
|
+
status: "ok"
|
|
1076
|
+
});
|
|
1077
|
+
const input = hydratedOptions.input ?? inferToolInput(tool, hydratedOptions.message);
|
|
1078
|
+
const outcome = await this.executeTool(run, tool, input, sandboxHandle, hydratedOptions.approve ?? false);
|
|
1079
|
+
run = outcome.run;
|
|
1080
|
+
if (outcome.waitingForApproval || outcome.waitingForInput || outcome.waitingForConnection) {
|
|
1081
|
+
await stopChannelLifecycle();
|
|
1082
|
+
await this.emitSpan("ai.assembly-line.turn", spanStartedAt, this.runSpanAttributes(run, {
|
|
1083
|
+
status: run.status
|
|
1084
|
+
}), {
|
|
1085
|
+
spanId: this.turnSpanId(run.id),
|
|
1086
|
+
status: "ok"
|
|
1087
|
+
});
|
|
1088
|
+
return this.result(run, response, outcome.waitingForApproval, outcome.waitingForInput, outcome.waitingForConnection);
|
|
1089
|
+
}
|
|
1090
|
+
response = typeof outcome.modelOutput === "string" ? outcome.modelOutput : JSON.stringify(outcome.modelOutput);
|
|
1091
|
+
}
|
|
1092
|
+
else {
|
|
1093
|
+
const loopInput = {
|
|
1094
|
+
run,
|
|
1095
|
+
bundle,
|
|
1096
|
+
sandboxHandle,
|
|
1097
|
+
message: hydratedOptions.message,
|
|
1098
|
+
channel,
|
|
1099
|
+
instructions: targetInstructions
|
|
1100
|
+
};
|
|
1101
|
+
if (hydratedOptions.turn)
|
|
1102
|
+
loopInput.turn = hydratedOptions.turn;
|
|
1103
|
+
if (conversation?.id) {
|
|
1104
|
+
loopInput.conversationId = conversation.id;
|
|
1105
|
+
loopInput.transcript = await this.loadConversationTranscript(conversation.id, run.id);
|
|
1106
|
+
}
|
|
1107
|
+
// A host-forced model wins over the resolver; the resolver wins over the manifest default.
|
|
1108
|
+
if (model)
|
|
1109
|
+
loopInput.model = model;
|
|
1110
|
+
else if (resolution?.model)
|
|
1111
|
+
loopInput.model = resolution.model;
|
|
1112
|
+
if (resolution?.defaultTools)
|
|
1113
|
+
loopInput.defaultToolNames = resolution.defaultTools;
|
|
1114
|
+
const outcome = await this.runHarnessLoop(loopInput);
|
|
1115
|
+
run = outcome.run;
|
|
1116
|
+
if (outcome.waitingForApproval || outcome.waitingForInput || outcome.waitingForConnection) {
|
|
1117
|
+
await stopChannelLifecycle();
|
|
1118
|
+
await this.emitSpan("ai.assembly-line.turn", spanStartedAt, this.runSpanAttributes(run, {
|
|
1119
|
+
status: run.status
|
|
1120
|
+
}), {
|
|
1121
|
+
spanId: this.turnSpanId(run.id),
|
|
1122
|
+
status: "ok"
|
|
1123
|
+
});
|
|
1124
|
+
return this.result(run, outcome.response, outcome.waitingForApproval, outcome.waitingForInput, outcome.waitingForConnection);
|
|
1125
|
+
}
|
|
1126
|
+
if (outcome.failed || outcome.controlStopped) {
|
|
1127
|
+
await stopChannelLifecycle();
|
|
1128
|
+
await sandboxHandle.dispose();
|
|
1129
|
+
return this.result(run, outcome.response, false, false, false);
|
|
1130
|
+
}
|
|
1131
|
+
response = outcome.response;
|
|
1132
|
+
structuredOutput = outcome.output;
|
|
1133
|
+
}
|
|
1134
|
+
const boundaryControl = await this.settleCompletionBoundaryControl(run);
|
|
1135
|
+
if (boundaryControl) {
|
|
1136
|
+
run = boundaryControl;
|
|
1137
|
+
await stopChannelLifecycle();
|
|
1138
|
+
await sandboxHandle.dispose();
|
|
1139
|
+
return this.result(run, response, false, false, false);
|
|
1140
|
+
}
|
|
1141
|
+
await stopChannelLifecycle();
|
|
1142
|
+
const result = await this.completeRun(run, sandboxHandle, response, channel, hydratedOptions.turn, conversation?.id);
|
|
1143
|
+
if (structuredOutput !== undefined)
|
|
1144
|
+
result.output = structuredOutput;
|
|
1145
|
+
await this.emitSpan("ai.assembly-line.turn", spanStartedAt, this.runSpanAttributes(result.run, {
|
|
1146
|
+
status: result.run.status
|
|
1147
|
+
}), {
|
|
1148
|
+
spanId: this.turnSpanId(result.run.id),
|
|
1149
|
+
status: result.run.status === "failed" ? "error" : "ok"
|
|
1150
|
+
});
|
|
1151
|
+
await this.emitSpan("assembly-line.run", spanStartedAt, {
|
|
1152
|
+
runId: run.id,
|
|
1153
|
+
status: result.run.status,
|
|
1154
|
+
agentRevision: this.manifest.agentRevision
|
|
1155
|
+
});
|
|
1156
|
+
return result;
|
|
1157
|
+
}
|
|
1158
|
+
catch (error) {
|
|
1159
|
+
// Fatal model errors terminalize with a durable reason; anything else is
|
|
1160
|
+
// evented + logged but left "running" so the recovery sweep can resume
|
|
1161
|
+
// from the latest continuation (the crash-durability contract).
|
|
1162
|
+
await handleRunExecutionError({ state: this.state, logger: this.logger }, run.id, error);
|
|
1163
|
+
throw error;
|
|
1164
|
+
}
|
|
1165
|
+
finally {
|
|
1166
|
+
heartbeat.stop();
|
|
1167
|
+
await stopChannelLifecycle();
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
/** Settle a control request that arrived during a forced direct-tool run (run-outcome.ts). */
|
|
1171
|
+
async settleCompletionBoundaryControl(run) {
|
|
1172
|
+
return settleCompletionBoundaryControlImpl({ state: this.state, runControlIntents: this.runControlIntents }, run);
|
|
1173
|
+
}
|
|
1174
|
+
/** Bump `updatedAt` while a run executes; enforces the wall-clock deadline (run-heartbeat.ts). */
|
|
1175
|
+
startRunHeartbeat(runId) {
|
|
1176
|
+
return startRunHeartbeatImpl({
|
|
1177
|
+
state: this.state,
|
|
1178
|
+
logger: this.logger,
|
|
1179
|
+
runHeartbeatMs: this.runHeartbeatMs,
|
|
1180
|
+
maxRunDurationMs: this.maxRunDurationMs,
|
|
1181
|
+
runControlIntents: this.runControlIntents,
|
|
1182
|
+
runDeadlines: this.runDeadlines,
|
|
1183
|
+
abortRunControllers: (id) => {
|
|
1184
|
+
for (const controller of this.runAbortControllers.get(id) ?? [])
|
|
1185
|
+
controller.abort();
|
|
1186
|
+
},
|
|
1187
|
+
debugSwallow: (message, fields) => this.debugSwallow(message, fields)
|
|
1188
|
+
}, runId);
|
|
1189
|
+
}
|
|
1190
|
+
registerRunAbort(runId, controller) {
|
|
1191
|
+
return registerRunAbortController(this.runAbortControllers, this.runDeadlines, runId, controller);
|
|
1192
|
+
}
|
|
1193
|
+
conversationContextHost() {
|
|
1194
|
+
const runtime = this;
|
|
1195
|
+
return {
|
|
1196
|
+
state: this.state,
|
|
1197
|
+
manifest: this.manifest,
|
|
1198
|
+
logger: this.logger,
|
|
1199
|
+
coreToolPolicy: this.coreToolPolicy,
|
|
1200
|
+
memoryStore: this.memoryStore,
|
|
1201
|
+
skillStore: this.skillStore,
|
|
1202
|
+
sourceLoader: this.sourceLoader,
|
|
1203
|
+
get contextPolicyPromise() {
|
|
1204
|
+
return runtime.contextPolicyPromise;
|
|
1205
|
+
},
|
|
1206
|
+
set contextPolicyPromise(value) {
|
|
1207
|
+
runtime.contextPolicyPromise = value;
|
|
1208
|
+
},
|
|
1209
|
+
loadChannelModule: (channel) => this.loadChannelModule(channel),
|
|
1210
|
+
channelContext: (channel) => this.channelContext(channel),
|
|
1211
|
+
warnSwallow: (message, fields) => this.warnSwallow(message, fields),
|
|
1212
|
+
memoryScopeForRun: (run) => this.memoryScopeForRun(run),
|
|
1213
|
+
durableAgentScope: () => this.durableAgentScope(),
|
|
1214
|
+
ensureSkillsSeeded: () => this.ensureSkillsSeeded(),
|
|
1215
|
+
skillScope: () => this.skillScope()
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
async prepareConversation(run, options, channel) {
|
|
1219
|
+
return prepareConversationImpl(this.conversationContextHost(), run, options, channel);
|
|
1220
|
+
}
|
|
1221
|
+
async recentHistory(conversationId) {
|
|
1222
|
+
return recentHistoryImpl(this.conversationContextHost(), conversationId);
|
|
1223
|
+
}
|
|
1224
|
+
async augmentChannelContext(channelName, turn, run) {
|
|
1225
|
+
return augmentChannelContextImpl(this.conversationContextHost(), channelName, turn, run);
|
|
1226
|
+
}
|
|
1227
|
+
async buildContextBundle(input) {
|
|
1228
|
+
return buildContextBundleImpl(this.conversationContextHost(), input);
|
|
1229
|
+
}
|
|
1230
|
+
harnessLoopHost() {
|
|
1231
|
+
const runtime = this;
|
|
1232
|
+
return {
|
|
1233
|
+
state: this.state,
|
|
1234
|
+
blob: this.blob,
|
|
1235
|
+
manifest: this.manifest,
|
|
1236
|
+
env: this.env,
|
|
1237
|
+
logger: this.logger,
|
|
1238
|
+
models: this.models,
|
|
1239
|
+
agentHarnessOverride: this.agentHarnessOverride,
|
|
1240
|
+
modelHarnesses: this.modelHarnesses,
|
|
1241
|
+
checkpointEveryIteration: this.checkpointEveryIteration,
|
|
1242
|
+
maxModelIterations: this.maxModelIterations,
|
|
1243
|
+
outputValidationMaxRetries: this.outputValidationMaxRetries,
|
|
1244
|
+
now: () => this.now(),
|
|
1245
|
+
shouldStopRun: (runId) => this.runControlIntents.has(runId) || this.runDeadlines.has(runId),
|
|
1246
|
+
runDeadlineExceeded: (runId) => this.runDeadlines.has(runId),
|
|
1247
|
+
registerRunAbort: (runId, controller) => this.registerRunAbort(runId, controller),
|
|
1248
|
+
maxRunDurationMs: this.maxRunDurationMs,
|
|
1249
|
+
runEventBus: this.runEventBus,
|
|
1250
|
+
connectionAuthorizationSessionStore: this.connectionAuthorizationSessionStore,
|
|
1251
|
+
get defaultAgentHarness() {
|
|
1252
|
+
return runtime.defaultAgentHarness;
|
|
1253
|
+
},
|
|
1254
|
+
set defaultAgentHarness(value) {
|
|
1255
|
+
runtime.defaultAgentHarness = value;
|
|
1256
|
+
},
|
|
1257
|
+
get instrumentationConfig() {
|
|
1258
|
+
return runtime.instrumentationConfig;
|
|
1259
|
+
},
|
|
1260
|
+
createConnectionRegistry: (channel, turn) => this.createConnectionRegistry(channel, turn),
|
|
1261
|
+
createConnectionRegistryForRun: (run, fallbackChannel, sandboxHandle) => this.createConnectionRegistryForRun(run, fallbackChannel, sandboxHandle),
|
|
1262
|
+
visibleToolSet: (defaultToolNames, activeSkills) => this.visibleToolSet(defaultToolNames, activeSkills),
|
|
1263
|
+
modelTools: (activeToolNames, connectionRegistry, discoveredConnectionTools) => this.modelTools(activeToolNames, connectionRegistry, discoveredConnectionTools),
|
|
1264
|
+
harnessExecuteTool: (call, state) => this.harnessExecuteTool(call, state),
|
|
1265
|
+
createCheckpoint: (input) => this.createCheckpoint(input),
|
|
1266
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1267
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1268
|
+
turnSpanId: (runId) => this.turnSpanId(runId)
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
async resolveAgentHarness(modelSpec) {
|
|
1272
|
+
return resolveAgentHarnessImpl(this.harnessLoopHost(), modelSpec);
|
|
1273
|
+
}
|
|
1274
|
+
piHarness() {
|
|
1275
|
+
return piHarnessImpl(this.harnessLoopHost());
|
|
1276
|
+
}
|
|
1277
|
+
async runHarnessLoop(input) {
|
|
1278
|
+
return runHarnessLoopImpl(this.harnessLoopHost(), input);
|
|
1279
|
+
}
|
|
1280
|
+
/** Load the conversation's stored transcript for resume, or undefined when disabled/absent. */
|
|
1281
|
+
async loadConversationTranscript(conversationId, runId) {
|
|
1282
|
+
return loadResumableConversationTranscriptImpl(this.conversationContextHost(), { state: this.state, createCheckpoint: (input) => this.createCheckpoint(input) }, conversationId, runId);
|
|
1283
|
+
}
|
|
1284
|
+
createHarnessContext(session, loopState, resumed) {
|
|
1285
|
+
return createHarnessContextImpl(this.harnessLoopHost(), session, loopState, resumed);
|
|
1286
|
+
}
|
|
1287
|
+
async persistHarnessContinuation(runId, session, continuation, pause) {
|
|
1288
|
+
return persistHarnessContinuationImpl(this.harnessLoopHost(), runId, session, continuation, pause);
|
|
1289
|
+
}
|
|
1290
|
+
channelIngressHost() {
|
|
1291
|
+
return {
|
|
1292
|
+
state: this.state,
|
|
1293
|
+
manifest: this.manifest,
|
|
1294
|
+
devMode: this.devMode,
|
|
1295
|
+
logger: this.logger,
|
|
1296
|
+
runSemaphore: this.runSemaphore,
|
|
1297
|
+
boot: () => this.boot(),
|
|
1298
|
+
loadChannelModule: (channel) => this.loadChannelModule(channel),
|
|
1299
|
+
channelContext: (channel) => this.channelContext(channel),
|
|
1300
|
+
agentEnabled: () => this.agentEnabled(),
|
|
1301
|
+
admitRunOrReject: () => this.admitRunOrReject(),
|
|
1302
|
+
enqueueConversationTurn: (input) => this.conversationTurnDispatcher.enqueue(input),
|
|
1303
|
+
run: (options) => this.run(options),
|
|
1304
|
+
dispatchAutomationEvent: (event) => this.dispatchAutomationEvent(event)
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
async dispatchHttpChannel(channelName, request) {
|
|
1308
|
+
return dispatchHttpChannelImpl(this.channelIngressHost(), channelName, request);
|
|
1309
|
+
}
|
|
1310
|
+
async acceptChannelTurn(channelName, input) {
|
|
1311
|
+
return acceptChannelTurnImpl(this.channelIngressHost(), channelName, input);
|
|
1312
|
+
}
|
|
1313
|
+
async startChannelIngress() {
|
|
1314
|
+
return startChannelIngressImpl(this.channelIngressHost());
|
|
1315
|
+
}
|
|
1316
|
+
replayResumeHost() {
|
|
1317
|
+
return {
|
|
1318
|
+
state: this.state,
|
|
1319
|
+
manifest: this.manifest,
|
|
1320
|
+
coreToolPolicy: this.coreToolPolicy,
|
|
1321
|
+
env: this.env,
|
|
1322
|
+
fetch: this.fetch,
|
|
1323
|
+
connectionAuthorizationSessionStore: this.connectionAuthorizationSessionStore,
|
|
1324
|
+
connectionGrantStore: this.connectionGrantStore,
|
|
1325
|
+
connectionCallbackBaseUrl: this.connectionCallbackBaseUrl,
|
|
1326
|
+
boot: () => this.boot(),
|
|
1327
|
+
initializeInstrumentation: () => this.initializeInstrumentation(),
|
|
1328
|
+
ensureDynamicConnections: () => this.ensureDynamicConnections(),
|
|
1329
|
+
withRunAdmission: (work) => this.withRunAdmission(work),
|
|
1330
|
+
listHydratedCheckpoints: (runId) => this.listHydratedCheckpoints(runId),
|
|
1331
|
+
resolveAgentHarness: (modelSpec) => this.resolveAgentHarness(modelSpec),
|
|
1332
|
+
buildContextBundle: (input) => this.buildContextBundle(input),
|
|
1333
|
+
createSandboxHandle: (getRun, setRun, getBundle) => this.createSandboxHandle(getRun, setRun, getBundle),
|
|
1334
|
+
executeToolWithRecord: (run, tool, toolCall, input, sandboxHandle, approvedToolCall) => this.executeToolWithRecord(run, tool, toolCall, input, sandboxHandle, approvedToolCall),
|
|
1335
|
+
executeConnectionToolWithRecord: (run, registry, toolName, toolCall, input) => this.executeConnectionToolWithRecord(run, registry, toolName, toolCall, input),
|
|
1336
|
+
createConnectionRegistry: (channel, turn) => this.createConnectionRegistry(channel, turn),
|
|
1337
|
+
createConnectionRegistryForRun: (run, fallbackChannel, sandboxHandle) => this.createConnectionRegistryForRun(run, fallbackChannel, sandboxHandle),
|
|
1338
|
+
createConnectionRegistryForSession: (session) => this.createConnectionRegistryForSession(session),
|
|
1339
|
+
mergedConnections: () => this.mergedConnections(),
|
|
1340
|
+
loadConnectionDefinition: (connection) => this.loadConnectionDefinition(connection),
|
|
1341
|
+
startRunHeartbeat: (runId) => this.startRunHeartbeat(runId),
|
|
1342
|
+
createHarnessContext: (session, loopState, resumed) => this.createHarnessContext(session, loopState, resumed),
|
|
1343
|
+
executeHarnessTurn: (harness, input, session, loopState, resumed) => executeHarnessTurnImpl(this.harnessLoopHost(), harness, input, session, loopState, resumed),
|
|
1344
|
+
persistHarnessContinuation: (runId, session, continuation, pause) => this.persistHarnessContinuation(runId, session, continuation, pause),
|
|
1345
|
+
createCheckpoint: (input) => this.createCheckpoint(input),
|
|
1346
|
+
result: (run, response, waitingForApproval, waitingForInput, waitingForConnection) => this.result(run, response, waitingForApproval, waitingForInput, waitingForConnection),
|
|
1347
|
+
completeRun: (run, sandboxHandle, response, channel, turn, conversationId) => this.completeRun(run, sandboxHandle, response, channel, turn, conversationId),
|
|
1348
|
+
runDeliveryChannel: (run) => this.runDeliveryChannel(run)
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
async replay(runId) {
|
|
1352
|
+
return replayImpl(this.replayResumeHost(), runId);
|
|
1353
|
+
}
|
|
1354
|
+
/** Resumes never consume run capacity (deadlock risk); they only count toward `onIdle()`. */
|
|
1355
|
+
async resumeApproval(runId) {
|
|
1356
|
+
const result = await this.withRunAdmission(() => this.resumeApprovalNow(runId));
|
|
1357
|
+
await this.conversationTurnDispatcher.settleRunResult(result);
|
|
1358
|
+
return result;
|
|
1359
|
+
}
|
|
1360
|
+
async resumeApprovalNow(runId) {
|
|
1361
|
+
return resumeApprovalNowImpl(this.replayResumeHost(), runId);
|
|
1362
|
+
}
|
|
1363
|
+
async completeConnectionAuthorizationCallback(callback) {
|
|
1364
|
+
const result = await completeConnectionAuthorizationCallbackImpl(this.replayResumeHost(), callback);
|
|
1365
|
+
if (result.runResult)
|
|
1366
|
+
await this.conversationTurnDispatcher.settleRunResult(result.runResult);
|
|
1367
|
+
return result;
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* Begin (or resume) the authorization flow for a named connection on behalf
|
|
1371
|
+
* of an operator surface such as a dashboard or CLI, outside any run. Backs
|
|
1372
|
+
* the node host's authenticated GET /openeve/connections/authorize route.
|
|
1373
|
+
* Idempotent by construction: an existing usable grant reports "connected"
|
|
1374
|
+
* and a pending session's challenge URL is reused, so this doubles as a
|
|
1375
|
+
* per-connection status probe while a consent flow is in flight. Connections
|
|
1376
|
+
* with subject "user" require the caller to supply the same user identity a
|
|
1377
|
+
* run would carry; otherwise they report unavailable (principal_required).
|
|
1378
|
+
*/
|
|
1379
|
+
async beginConnectionAuthorization(connectionName, session = {}) {
|
|
1380
|
+
return beginConnectionAuthorizationImpl(this.toolExecutionHost(), connectionName, session);
|
|
1381
|
+
}
|
|
1382
|
+
/** Resumes never consume run capacity (deadlock risk); they only count toward `onIdle()`. */
|
|
1383
|
+
async resumeInput(runId, answer) {
|
|
1384
|
+
const result = await this.withRunAdmission(() => this.resumeInputNow(runId, answer));
|
|
1385
|
+
await this.conversationTurnDispatcher.settleRunResult(result);
|
|
1386
|
+
return result;
|
|
1387
|
+
}
|
|
1388
|
+
async resumeInputNow(runId, answer) {
|
|
1389
|
+
return resumeInputNowImpl(this.replayResumeHost(), runId, answer);
|
|
1390
|
+
}
|
|
1391
|
+
/** Request cooperative cancellation, or synchronously cancel a parked run. */
|
|
1392
|
+
async cancelRun(runId) {
|
|
1393
|
+
const run = await requestRunControlImpl(this.operatorControlsHost(), runId, "cancel");
|
|
1394
|
+
if (run.status === "cancelled")
|
|
1395
|
+
await this.conversationTurnDispatcher.settleRunRecord(run);
|
|
1396
|
+
return run;
|
|
1397
|
+
}
|
|
1398
|
+
/** Request cooperative suspension of a currently running run. */
|
|
1399
|
+
async suspendRun(runId) {
|
|
1400
|
+
return requestRunControlImpl(this.operatorControlsHost(), runId, "suspend");
|
|
1401
|
+
}
|
|
1402
|
+
/** Resume a deliberately suspended run from its latest durable continuation. */
|
|
1403
|
+
async resumeSuspended(runId) {
|
|
1404
|
+
const result = await this.withRunAdmission(() => resumeSuspendedNowImpl(this.replayResumeHost(), runId));
|
|
1405
|
+
await this.conversationTurnDispatcher.settleRunResult(result);
|
|
1406
|
+
return result;
|
|
1407
|
+
}
|
|
1408
|
+
/** Read the durable ingress kill-switch for this stable agent identity. */
|
|
1409
|
+
async getAgentControl() {
|
|
1410
|
+
return getAgentControlImpl(this.operatorControlsHost());
|
|
1411
|
+
}
|
|
1412
|
+
/** Enable or disable new channel ingress without affecting in-flight runs or resumes. */
|
|
1413
|
+
async setAgentEnabled(enabled, metadata = {}) {
|
|
1414
|
+
const result = await setAgentEnabledImpl(this.operatorControlsHost(), enabled, metadata);
|
|
1415
|
+
if (enabled)
|
|
1416
|
+
this.conversationTurnDispatcher.requestDrain();
|
|
1417
|
+
return result;
|
|
1418
|
+
}
|
|
1419
|
+
/** Quiesce new ingress and background dispatch while in-flight work drains. */
|
|
1420
|
+
async setAgentMaintenance(maintenance, metadata = {}) {
|
|
1421
|
+
const result = await setAgentMaintenanceImpl(this.operatorControlsHost(), maintenance, metadata);
|
|
1422
|
+
if (!maintenance)
|
|
1423
|
+
this.conversationTurnDispatcher.requestDrain();
|
|
1424
|
+
return result;
|
|
1425
|
+
}
|
|
1426
|
+
async agentEnabled() {
|
|
1427
|
+
return (await this.getAgentControl()).acceptingWork;
|
|
1428
|
+
}
|
|
1429
|
+
operatorControlsHost() {
|
|
1430
|
+
return {
|
|
1431
|
+
state: this.state,
|
|
1432
|
+
boot: () => this.boot(),
|
|
1433
|
+
durableAgentScope: () => this.durableAgentScope(),
|
|
1434
|
+
cacheRunControl: (runId, intent) => {
|
|
1435
|
+
if (intent)
|
|
1436
|
+
this.runControlIntents.set(runId, intent);
|
|
1437
|
+
else
|
|
1438
|
+
this.runControlIntents.delete(runId);
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
}
|
|
1442
|
+
async resumeHarnessLoop(run, harness, restored, resume) {
|
|
1443
|
+
return resumeHarnessLoopImpl(this.replayResumeHost(), run, harness, restored, resume);
|
|
1444
|
+
}
|
|
1445
|
+
subagentExecutionHost() {
|
|
1446
|
+
return {
|
|
1447
|
+
state: this.state,
|
|
1448
|
+
manifest: this.manifest,
|
|
1449
|
+
sourceLoader: this.sourceLoader,
|
|
1450
|
+
resolveAgentHarness: (modelSpec) => this.resolveAgentHarness(modelSpec),
|
|
1451
|
+
replay: (runId) => this.replay(runId),
|
|
1452
|
+
listHydratedCheckpoints: (runId) => this.listHydratedCheckpoints(runId),
|
|
1453
|
+
buildContextBundle: (input) => this.buildContextBundle(input),
|
|
1454
|
+
createSandboxHandle: (getRun, setRun, getBundle) => this.createSandboxHandle(getRun, setRun, getBundle),
|
|
1455
|
+
startRunHeartbeat: (runId) => this.startRunHeartbeat(runId),
|
|
1456
|
+
runHarnessLoop: (input) => this.runHarnessLoop(input),
|
|
1457
|
+
resumeHarnessLoop: (run, harness, restored, resume) => this.resumeHarnessLoop(run, harness, restored, resume),
|
|
1458
|
+
completeRun: (run, sandboxHandle, response, channel, turn, conversationId) => this.completeRun(run, sandboxHandle, response, channel, turn, conversationId),
|
|
1459
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1460
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1461
|
+
turnSpanId: (runId) => this.turnSpanId(runId)
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
async runSubagent(parentRunId, subagentName, task) {
|
|
1465
|
+
return runSubagentImpl(this.subagentExecutionHost(), parentRunId, subagentName, task);
|
|
1466
|
+
}
|
|
1467
|
+
async readSubagent(childRunId, cursor) {
|
|
1468
|
+
return readSubagentImpl(this.subagentExecutionHost(), childRunId, cursor);
|
|
1469
|
+
}
|
|
1470
|
+
async sendSubagentFollowup(childRunId, message) {
|
|
1471
|
+
return sendSubagentFollowupImpl(this.subagentExecutionHost(), childRunId, message);
|
|
1472
|
+
}
|
|
1473
|
+
async loadSkill(runId, skillName) {
|
|
1474
|
+
const loaded = await this.skillLoadDetails(skillName);
|
|
1475
|
+
const output = {
|
|
1476
|
+
name: loaded.name,
|
|
1477
|
+
skillName: loaded.name,
|
|
1478
|
+
description: loaded.description,
|
|
1479
|
+
origin: loaded.origin,
|
|
1480
|
+
path: loaded.path,
|
|
1481
|
+
instructions: loaded.instructions
|
|
1482
|
+
};
|
|
1483
|
+
if (loaded.declaredTools.length > 0)
|
|
1484
|
+
output.declaredTools = loaded.declaredTools;
|
|
1485
|
+
await this.state.appendEvent(runId, "skill.loaded", {
|
|
1486
|
+
skill: loaded.name,
|
|
1487
|
+
origin: loaded.origin,
|
|
1488
|
+
path: loaded.path
|
|
1489
|
+
});
|
|
1490
|
+
return output;
|
|
1491
|
+
}
|
|
1492
|
+
async activateSkill(runId, skillName) {
|
|
1493
|
+
await this.loadSkill(runId, skillName);
|
|
1494
|
+
return visibleToolsForSkills(this.manifest);
|
|
1495
|
+
}
|
|
1496
|
+
scheduleExecutionHost() {
|
|
1497
|
+
return {
|
|
1498
|
+
manifest: this.manifest,
|
|
1499
|
+
state: this.state,
|
|
1500
|
+
blob: this.blob,
|
|
1501
|
+
env: this.env,
|
|
1502
|
+
fetch: this.fetch,
|
|
1503
|
+
logger: this.logger,
|
|
1504
|
+
memoryStore: this.memoryStore,
|
|
1505
|
+
skillStore: this.skillStore,
|
|
1506
|
+
scheduleStore: this.scheduleStore,
|
|
1507
|
+
schedulesConfig: this.schedulesConfig,
|
|
1508
|
+
schedulerTickMs: this.schedulerTickMs,
|
|
1509
|
+
scheduleMaxConsecutiveFailures: this.scheduleMaxConsecutiveFailures,
|
|
1510
|
+
sourceLoader: this.sourceLoader,
|
|
1511
|
+
boot: () => this.boot(),
|
|
1512
|
+
now: () => this.now(),
|
|
1513
|
+
admitRunOrReject: () => this.admitRunOrReject(),
|
|
1514
|
+
run: (options) => this.run(options),
|
|
1515
|
+
latestRunFailureMessage: (runId) => this.latestRunFailureMessage(runId),
|
|
1516
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1517
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1518
|
+
turnSpanId: (runId) => this.turnSpanId(runId),
|
|
1519
|
+
createSandboxHandle: (getRun, setRun, getBundle) => this.createSandboxHandle(getRun, setRun, getBundle),
|
|
1520
|
+
createMemoryToolApi: (run) => this.createMemoryToolApi(run),
|
|
1521
|
+
createResourceToolApi: (run, sandboxHandle) => this.createResourceToolApi(run, sandboxHandle),
|
|
1522
|
+
durableStep: (runId, key, fn, options) => this.durableStep(runId, key, fn, options),
|
|
1523
|
+
memoryScopeForRun: (run) => this.memoryScopeForRun(run),
|
|
1524
|
+
mergedConnections: () => this.mergedConnections(),
|
|
1525
|
+
skillScope: () => this.skillScope(),
|
|
1526
|
+
agentEnabled: () => this.agentEnabled()
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
async registerManifestSchedules() {
|
|
1530
|
+
return registerManifestSchedulesImpl(this.scheduleExecutionHost());
|
|
1531
|
+
}
|
|
1532
|
+
async registerManifestAutomations() {
|
|
1533
|
+
return this.registerManifestSchedules();
|
|
1534
|
+
}
|
|
1535
|
+
/** @deprecated Use `runDueAutomations`. */
|
|
1536
|
+
async runDueSchedules(options = {}) {
|
|
1537
|
+
return runDueSchedulesImpl(this.scheduleExecutionHost(), options);
|
|
1538
|
+
}
|
|
1539
|
+
async runDueAutomations(options = {}) {
|
|
1540
|
+
return this.runDueSchedules(options);
|
|
1541
|
+
}
|
|
1542
|
+
async dispatchAutomationEvent(event) {
|
|
1543
|
+
return dispatchAutomationEventImpl(this.scheduleExecutionHost(), event);
|
|
1544
|
+
}
|
|
1545
|
+
normalizeScheduleTriggerDefinition(value) {
|
|
1546
|
+
return normalizeScheduleTriggerDefinitionImpl(this.scheduleExecutionHost(), value);
|
|
1547
|
+
}
|
|
1548
|
+
async startSchedulerLoop() {
|
|
1549
|
+
if (!this.shouldStartScheduler())
|
|
1550
|
+
return undefined;
|
|
1551
|
+
return this.scheduler.start(this);
|
|
1552
|
+
}
|
|
1553
|
+
async startSchedulerPollingLoop() {
|
|
1554
|
+
return startSchedulerPollingLoopImpl(this.scheduleExecutionHost());
|
|
1555
|
+
}
|
|
1556
|
+
shouldStartScheduler() {
|
|
1557
|
+
if (this.schedulerEnabled === false)
|
|
1558
|
+
return false;
|
|
1559
|
+
if (this.env.OPENEVE_SCHEDULER_ENABLED === "false" || this.env.OPENEVE_SCHEDULER_ENABLED === "0")
|
|
1560
|
+
return false;
|
|
1561
|
+
return true;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Subscribe to a run's live event stream: every durable event as it is
|
|
1565
|
+
* persisted plus ephemeral `model.response_delta` token deltas. Returns an
|
|
1566
|
+
* unsubscribe function. For catch-up, replay `listEvents(runId)` first and
|
|
1567
|
+
* dedupe by `sequence`.
|
|
1568
|
+
*/
|
|
1569
|
+
subscribeRunStream(runId, listener) {
|
|
1570
|
+
return this.runEventBus.subscribe(runId, listener);
|
|
1571
|
+
}
|
|
1572
|
+
/** Staleness-guarded orphaned-run sweep. See {@link RunRecoveryOptions} for tuning. */
|
|
1573
|
+
async recoverIncompleteRuns(options = {}) {
|
|
1574
|
+
if (!(await this.agentEnabled()))
|
|
1575
|
+
return [];
|
|
1576
|
+
const host = {
|
|
1577
|
+
state: this.state,
|
|
1578
|
+
logger: this.logger,
|
|
1579
|
+
now: this.now,
|
|
1580
|
+
runHeartbeatMs: this.runHeartbeatMs,
|
|
1581
|
+
sandboxSyncMaxAttempts: this.sandboxSyncMaxAttempts,
|
|
1582
|
+
deliveryQueueMaxAttempts: this.deliveryQueueMaxAttempts,
|
|
1583
|
+
resumeRunFromContinuation: (run, context) => this.withRunAdmission(() => this.resumeRunFromContinuation(run, context)),
|
|
1584
|
+
listHydratedCheckpoints: (runId) => this.listHydratedCheckpoints(runId)
|
|
1585
|
+
};
|
|
1586
|
+
const recovered = await recoverIncompleteRunsImpl(host, options);
|
|
1587
|
+
for (const run of recovered) {
|
|
1588
|
+
await this.conversationTurnDispatcher.settleRunRecord(run);
|
|
1589
|
+
}
|
|
1590
|
+
await this.conversationTurnDispatcher.recover();
|
|
1591
|
+
return recovered;
|
|
1592
|
+
}
|
|
1593
|
+
/** Resume an orphaned run in place from its latest persisted continuation checkpoint (replay-resume.ts). */
|
|
1594
|
+
async resumeRunFromContinuation(run, context) {
|
|
1595
|
+
return resumeRunFromContinuationImpl(this.replayResumeHost(), run, context);
|
|
1596
|
+
}
|
|
1597
|
+
/** Start delivery, sandbox-sync, conversation-turn, and orphan-recovery workers. */
|
|
1598
|
+
startBackgroundWorkers(options = {}) {
|
|
1599
|
+
return startBackgroundWorkersImpl({
|
|
1600
|
+
env: this.env,
|
|
1601
|
+
logger: this.logger,
|
|
1602
|
+
runRecoveryIntervalMs: this.runRecoveryIntervalMs,
|
|
1603
|
+
startDeliveryWorker: (workerOptions) => this.startDeliveryWorker(workerOptions),
|
|
1604
|
+
startSandboxSyncWorker: (workerOptions) => this.startSandboxSyncWorker(workerOptions),
|
|
1605
|
+
startConversationTurnWorker: (workerOptions) => this.conversationTurnDispatcher.startWorker(workerOptions?.intervalMs),
|
|
1606
|
+
recoverIncompleteRuns: (recoveryOptions) => this.recoverIncompleteRuns(recoveryOptions),
|
|
1607
|
+
agentEnabled: () => this.agentEnabled()
|
|
1608
|
+
}, options);
|
|
1609
|
+
}
|
|
1610
|
+
deliveryQueueHost() {
|
|
1611
|
+
return {
|
|
1612
|
+
state: this.state,
|
|
1613
|
+
logger: this.logger,
|
|
1614
|
+
now: this.now,
|
|
1615
|
+
leaseMs: this.deliveryQueueLeaseMs,
|
|
1616
|
+
batchSize: this.deliveryQueueBatchSize,
|
|
1617
|
+
agentEnabled: () => this.agentEnabled(),
|
|
1618
|
+
sendQueuedDelivery: async (delivery) => {
|
|
1619
|
+
const response = typeof delivery.payload.response === "string" ? delivery.payload.response : "";
|
|
1620
|
+
return this.sendDelivery(delivery, response, undefined);
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
/** Drain due deferred deliveries once: recover expired leases, lease, send, settle. */
|
|
1625
|
+
async runDueDeliveries(options = {}) {
|
|
1626
|
+
return runDueDeliveriesImpl(this.deliveryQueueHost(), options);
|
|
1627
|
+
}
|
|
1628
|
+
startDeliveryWorker(options = {}) {
|
|
1629
|
+
const intervalMs = positiveLimit(options.intervalMs, this.deliveryQueueIntervalMs);
|
|
1630
|
+
return startDeliveryWorkerImpl(this.deliveryQueueHost(), { ...options, intervalMs });
|
|
1631
|
+
}
|
|
1632
|
+
/** The run's originating channel, for routing deliveries on resume/degrade paths. */
|
|
1633
|
+
runDeliveryChannel(run) {
|
|
1634
|
+
return typeof run.input.channel === "string" && run.input.channel ? run.input.channel : "local";
|
|
1635
|
+
}
|
|
1636
|
+
deliverySendHost() {
|
|
1637
|
+
return {
|
|
1638
|
+
state: this.state,
|
|
1639
|
+
blob: this.blob,
|
|
1640
|
+
logger: this.logger,
|
|
1641
|
+
env: this.env,
|
|
1642
|
+
manifest: this.manifest,
|
|
1643
|
+
devMode: this.devMode,
|
|
1644
|
+
deliveryMode: this.deliveryMode,
|
|
1645
|
+
now: this.now,
|
|
1646
|
+
sandboxSyncInline: this.sandboxSyncInline,
|
|
1647
|
+
deliveryQueueLeaseMs: this.deliveryQueueLeaseMs,
|
|
1648
|
+
deliveryQueueMaxAttempts: this.deliveryQueueMaxAttempts,
|
|
1649
|
+
sandboxSyncMaxAttempts: this.sandboxSyncMaxAttempts,
|
|
1650
|
+
result: (run, response, waitingForApproval, waitingForInput, waitingForConnection) => this.result(run, response, waitingForApproval, waitingForInput, waitingForConnection),
|
|
1651
|
+
sandboxSessionKey: (run) => this.sandboxSessionKey(run),
|
|
1652
|
+
debugSwallow: (message, fields) => this.debugSwallow(message, fields),
|
|
1653
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1654
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1655
|
+
turnSpanId: (runId) => this.turnSpanId(runId),
|
|
1656
|
+
captureSandboxSnapshot: (run, sandboxSession, stage) => this.captureSandboxSnapshot(run, sandboxSession, stage),
|
|
1657
|
+
loadChannelModule: (channel) => this.loadChannelModule(channel),
|
|
1658
|
+
channelContext: (channel) => this.channelContext(channel)
|
|
1659
|
+
};
|
|
1660
|
+
}
|
|
1661
|
+
async completeRun(run, sandboxHandle, response, channel, turn, conversationId) {
|
|
1662
|
+
return completeRunImpl(this.deliverySendHost(), run, sandboxHandle, response, channel, turn, conversationId);
|
|
1663
|
+
}
|
|
1664
|
+
async latestRunFailureMessage(runId) {
|
|
1665
|
+
return latestRunFailureMessageImpl(this.deliverySendHost(), runId);
|
|
1666
|
+
}
|
|
1667
|
+
async enqueueSandboxSyncAfterDelivery(run, sandboxSession) {
|
|
1668
|
+
return enqueueSandboxSyncAfterDeliveryImpl(this.deliverySendHost(), run, sandboxSession);
|
|
1669
|
+
}
|
|
1670
|
+
sandboxSyncWorkerHost() {
|
|
1671
|
+
return {
|
|
1672
|
+
state: this.state,
|
|
1673
|
+
blob: this.blob,
|
|
1674
|
+
sandbox: this.sandbox,
|
|
1675
|
+
logger: this.logger,
|
|
1676
|
+
env: this.env,
|
|
1677
|
+
now: this.now,
|
|
1678
|
+
sandboxSyncBatchSize: this.sandboxSyncBatchSize,
|
|
1679
|
+
sandboxSyncLeaseMs: this.sandboxSyncLeaseMs,
|
|
1680
|
+
sandboxSnapshotPolicy: this.sandboxSnapshotPolicy,
|
|
1681
|
+
readSandboxTombstonesWithMissingProjectedFiles: (sandbox) => this.readSandboxTombstonesWithMissingProjectedFiles(sandbox),
|
|
1682
|
+
syncMemoryFromSandbox: (run, sandboxSession, tombstones) => this.syncMemoryFromSandbox(run, sandboxSession, tombstones),
|
|
1683
|
+
syncSkillsFromSandbox: (run, sandboxSession, tombstones) => this.syncSkillsFromSandbox(run, sandboxSession, tombstones),
|
|
1684
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1685
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1686
|
+
turnSpanId: (runId) => this.turnSpanId(runId),
|
|
1687
|
+
warnSwallow: (message, fields) => this.warnSwallow(message, fields),
|
|
1688
|
+
createCheckpoint: (input) => this.createCheckpoint(input),
|
|
1689
|
+
sandboxSessionKey: (run) => this.sandboxSessionKey(run),
|
|
1690
|
+
agentEnabled: () => this.agentEnabled()
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
async sandboxSyncDiagnostics(options = {}) {
|
|
1694
|
+
return sandboxSyncDiagnosticsImpl(this.sandboxSyncWorkerHost(), options);
|
|
1695
|
+
}
|
|
1696
|
+
async inspectSandboxSyncJob(jobId, options = {}) {
|
|
1697
|
+
return inspectSandboxSyncJobImpl(this.sandboxSyncWorkerHost(), jobId, options);
|
|
1698
|
+
}
|
|
1699
|
+
async retrySandboxSyncJob(jobId, options = {}) {
|
|
1700
|
+
return retrySandboxSyncJobImpl(this.sandboxSyncWorkerHost(), jobId, options);
|
|
1701
|
+
}
|
|
1702
|
+
async runDueSandboxSyncJobs(options = {}) {
|
|
1703
|
+
return runDueSandboxSyncJobsImpl(this.sandboxSyncWorkerHost(), options);
|
|
1704
|
+
}
|
|
1705
|
+
startSandboxSyncWorker(options = {}) {
|
|
1706
|
+
return startSandboxSyncWorkerImpl(this.sandboxSyncWorkerHost(), options);
|
|
1707
|
+
}
|
|
1708
|
+
async captureSandboxSnapshot(run, sandboxSession, stage) {
|
|
1709
|
+
return captureSandboxSnapshotImpl(this.sandboxSyncWorkerHost(), run, sandboxSession, stage);
|
|
1710
|
+
}
|
|
1711
|
+
async disposeSandboxSession(runId, sandboxSession) {
|
|
1712
|
+
return disposeSandboxSessionImpl(this.sandboxSyncWorkerHost(), runId, sandboxSession);
|
|
1713
|
+
}
|
|
1714
|
+
async beginChannelTurn(channelName, turn) {
|
|
1715
|
+
return beginChannelTurnImpl(this.deliverySendHost(), channelName, turn);
|
|
1716
|
+
}
|
|
1717
|
+
async recordChannelTurnStart(start, run, channelName) {
|
|
1718
|
+
return recordChannelTurnStartImpl(this.deliverySendHost(), start, run, channelName);
|
|
1719
|
+
}
|
|
1720
|
+
async stopUnclaimedChannelTurn(start, channelName) {
|
|
1721
|
+
return stopUnclaimedChannelTurnImpl(this.deliverySendHost(), start, channelName);
|
|
1722
|
+
}
|
|
1723
|
+
async stopChannelTurn(lifecycle, run, channelName) {
|
|
1724
|
+
return stopChannelTurnImpl(this.deliverySendHost(), lifecycle, run, channelName);
|
|
1725
|
+
}
|
|
1726
|
+
async sendDelivery(delivery, response, turn) {
|
|
1727
|
+
return sendDeliveryImpl(this.deliverySendHost(), delivery, response, turn);
|
|
1728
|
+
}
|
|
1729
|
+
visibleToolSet(defaultToolNames, activeSkills) {
|
|
1730
|
+
return visibleToolSetImpl(this.toolExecutionHost(), defaultToolNames, activeSkills);
|
|
1731
|
+
}
|
|
1732
|
+
async skillLoadDetails(skillName) {
|
|
1733
|
+
return skillLoadDetailsImpl(this.toolExecutionHost(), skillName);
|
|
1734
|
+
}
|
|
1735
|
+
async instructionsForRunTarget(run, target, baseInstructions) {
|
|
1736
|
+
return instructionsForRunTargetImpl({ appendEvent: (runId, type, data) => this.state.appendEvent(runId, type, data), skillLoadDetails: (skillName) => this.skillLoadDetails(skillName) }, run, target, baseInstructions);
|
|
1737
|
+
}
|
|
1738
|
+
async modelTools(activeToolNames, connectionRegistry, discoveredConnectionTools = new Map()) {
|
|
1739
|
+
return modelToolsImpl(this.toolExecutionHost(), activeToolNames, connectionRegistry, discoveredConnectionTools);
|
|
1740
|
+
}
|
|
1741
|
+
async harnessExecuteTool(call, state) {
|
|
1742
|
+
return harnessExecuteToolImpl(this.toolExecutionHost(), call, state);
|
|
1743
|
+
}
|
|
1744
|
+
createConnectionRegistry(channel, turn) {
|
|
1745
|
+
return createConnectionRegistryImpl(this.toolExecutionHost(), channel, turn);
|
|
1746
|
+
}
|
|
1747
|
+
createConnectionRegistryForRun(run, fallbackChannel, sandboxHandle) {
|
|
1748
|
+
return createConnectionRegistryForRunImpl(this.toolExecutionHost(), run, fallbackChannel, sandboxHandle);
|
|
1749
|
+
}
|
|
1750
|
+
createConnectionRegistryForSession(session) {
|
|
1751
|
+
return createConnectionRegistryForSessionImpl(this.toolExecutionHost(), session);
|
|
1752
|
+
}
|
|
1753
|
+
async executeConnectionToolWithRecord(run, registry, toolName, toolCall, input) {
|
|
1754
|
+
return executeConnectionToolWithRecordImpl(this.toolExecutionHost(), run, registry, toolName, toolCall, input);
|
|
1755
|
+
}
|
|
1756
|
+
async loadConnectionDefinition(connection) {
|
|
1757
|
+
const inline = this.dynamicConnectionsCache?.defs.get(connection.name);
|
|
1758
|
+
if (inline)
|
|
1759
|
+
return inline;
|
|
1760
|
+
const module = await this.sourceLoader.load(connection.source);
|
|
1761
|
+
return module.default;
|
|
1762
|
+
}
|
|
1763
|
+
async loadChannelModule(channel) {
|
|
1764
|
+
return loadChannelModuleImpl((source) => this.sourceLoader.load(source), channel);
|
|
1765
|
+
}
|
|
1766
|
+
async channelAttachmentResolver(channel, trustedProvider) {
|
|
1767
|
+
return channelAttachmentResolverImpl({
|
|
1768
|
+
loadChannelModule: (target) => this.loadChannelModule(target),
|
|
1769
|
+
channelContext: (target) => this.channelContext(target),
|
|
1770
|
+
channelProvider: compiledChannelProvider,
|
|
1771
|
+
warnSwallow: (message, fields) => this.warnSwallow(message, fields)
|
|
1772
|
+
}, channel, trustedProvider);
|
|
1773
|
+
}
|
|
1774
|
+
channelContext(channel) {
|
|
1775
|
+
return {
|
|
1776
|
+
channel,
|
|
1777
|
+
agentScope: this.durableAgentScope(),
|
|
1778
|
+
connections: this.connections,
|
|
1779
|
+
env: this.env,
|
|
1780
|
+
fetch: this.fetch,
|
|
1781
|
+
state: this.state,
|
|
1782
|
+
blob: this.blob
|
|
1783
|
+
};
|
|
1784
|
+
}
|
|
1785
|
+
missingRequiredConnections() {
|
|
1786
|
+
return this.manifest.connections
|
|
1787
|
+
.filter((connection) => connection.required && connection.protocol === "declaration")
|
|
1788
|
+
.map((connection) => connection.name)
|
|
1789
|
+
.filter((name) => this.connections[name] === undefined);
|
|
1790
|
+
}
|
|
1791
|
+
async emitSpan(name, startedAt, attributes, options = {}) {
|
|
1792
|
+
return emitTelemetrySpanImpl(this.telemetry, { name, startedAt, attributes, options, traceIdForRun: (runId) => this.traceIdForRun(runId), randomHex, timestamp });
|
|
1793
|
+
}
|
|
1794
|
+
async initializeInstrumentation() {
|
|
1795
|
+
if (this.instrumentationLoaded || !this.manifest.instrumentation) {
|
|
1796
|
+
this.instrumentationLoaded = true;
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
const instrumentation = await this.loadInstrumentationModule();
|
|
1800
|
+
const defaultExport = instrumentation.default;
|
|
1801
|
+
const definition = isInstrumentationDefinition(defaultExport) ? defaultExport : undefined;
|
|
1802
|
+
// Host/gateway-supplied instrumentation wins over instrumentation.ts, mirroring
|
|
1803
|
+
// the telemetry-sink precedence below.
|
|
1804
|
+
if (definition && !this.hostInstrumentationProvided) {
|
|
1805
|
+
this.instrumentationConfig = {
|
|
1806
|
+
recordInputs: definition.recordInputs ?? false,
|
|
1807
|
+
recordOutputs: definition.recordOutputs ?? false,
|
|
1808
|
+
functionId: definition.functionId ?? definition.serviceName ?? this.agentName(),
|
|
1809
|
+
serviceName: definition.serviceName ?? this.agentName(),
|
|
1810
|
+
contentCapture: normalizeCapturePolicy(definition.captureContent)
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
const setupResult = definition?.setup
|
|
1814
|
+
? await definition.setup({
|
|
1815
|
+
agentName: this.agentName(),
|
|
1816
|
+
manifest: this.manifest,
|
|
1817
|
+
env: this.env
|
|
1818
|
+
})
|
|
1819
|
+
: undefined;
|
|
1820
|
+
const setupSink = telemetrySinkFromSetupResult(setupResult);
|
|
1821
|
+
const exportedSink = instrumentation.telemetry ?? definition?.telemetry;
|
|
1822
|
+
const sink = setupSink ?? exportedSink;
|
|
1823
|
+
if (!this.hostTelemetryProvided && isTelemetrySink(sink)) {
|
|
1824
|
+
this.telemetry = sink;
|
|
1825
|
+
}
|
|
1826
|
+
this.instrumentationLoaded = true;
|
|
1827
|
+
}
|
|
1828
|
+
agentName() {
|
|
1829
|
+
return this.manifest.agent.name ?? this.manifest.agent.description ?? `openeve-${this.manifest.agentRevision.slice(0, 12)}`;
|
|
1830
|
+
}
|
|
1831
|
+
traceIdForRun(runId) {
|
|
1832
|
+
return createHash("sha256").update(runId).digest("hex").slice(0, 32);
|
|
1833
|
+
}
|
|
1834
|
+
spanIdFor(runId, scope) {
|
|
1835
|
+
return createHash("sha256").update(runId).update(":").update(scope).digest("hex").slice(0, 16);
|
|
1836
|
+
}
|
|
1837
|
+
runSpanAttributes(run, extra = {}) {
|
|
1838
|
+
return runSpanAttributesImpl(this.manifest.agentRevision, this.instrumentationConfig, run, extra);
|
|
1839
|
+
}
|
|
1840
|
+
/** Tool argument/result span attributes, gated on the content-capture policy. */
|
|
1841
|
+
toolContentAttributes(input, output) {
|
|
1842
|
+
const policy = this.instrumentationConfig.contentCapture;
|
|
1843
|
+
if (!policy.includeToolIO)
|
|
1844
|
+
return {};
|
|
1845
|
+
const attributes = { "gen_ai.tool.input": redactTruncateJson(input, policy) };
|
|
1846
|
+
if (output !== undefined)
|
|
1847
|
+
attributes["gen_ai.tool.output"] = redactTruncateJson(output, policy);
|
|
1848
|
+
return attributes;
|
|
1849
|
+
}
|
|
1850
|
+
turnSpanId(runId) {
|
|
1851
|
+
return this.spanIdFor(runId, "turn");
|
|
1852
|
+
}
|
|
1853
|
+
toolExecutionHost() {
|
|
1854
|
+
return {
|
|
1855
|
+
state: this.state,
|
|
1856
|
+
env: this.env,
|
|
1857
|
+
fetch: this.fetch,
|
|
1858
|
+
manifest: this.manifest,
|
|
1859
|
+
coreToolPolicy: this.coreToolPolicy,
|
|
1860
|
+
skillStore: this.skillStore,
|
|
1861
|
+
memoryStore: this.memoryStore,
|
|
1862
|
+
sandbox: this.sandbox,
|
|
1863
|
+
connections: this.connections,
|
|
1864
|
+
connectionGrantStore: this.connectionGrantStore,
|
|
1865
|
+
connectionAuthorizationSessionStore: this.connectionAuthorizationSessionStore,
|
|
1866
|
+
connectionCallbackBaseUrl: this.connectionCallbackBaseUrl,
|
|
1867
|
+
toolOutputMaxChars: this.toolOutputMaxChars,
|
|
1868
|
+
toolTimeoutMs: this.toolTimeoutMs,
|
|
1869
|
+
sandboxSyncMaxAttempts: this.sandboxSyncMaxAttempts,
|
|
1870
|
+
skillsConfig: this.skillsConfig,
|
|
1871
|
+
schedulesConfig: this.schedulesConfig,
|
|
1872
|
+
connectionsConfig: this.connectionsConfig,
|
|
1873
|
+
ensureSkillsSeeded: () => this.ensureSkillsSeeded(),
|
|
1874
|
+
skillScope: () => this.skillScope(),
|
|
1875
|
+
scheduleScopeForRun: (run) => this.scheduleScopeForRun(run),
|
|
1876
|
+
memoryScopeForRun: (run) => this.memoryScopeForRun(run),
|
|
1877
|
+
sandboxSessionKey: (run) => this.sandboxSessionKey(run),
|
|
1878
|
+
mergedConnections: () => this.mergedConnections(),
|
|
1879
|
+
loadConnectionDefinition: (connection) => this.loadConnectionDefinition(connection),
|
|
1880
|
+
loadTool: (tool, run) => this.loadTool(tool, run),
|
|
1881
|
+
runSubagent: (parentRunId, subagentName, task) => this.runSubagent(parentRunId, subagentName, task),
|
|
1882
|
+
projectSkillIntoSandbox: (run, sandbox, skillName) => this.projectSkillIntoSandbox(run, sandbox, skillName),
|
|
1883
|
+
hydrateLogicalPathForTool: (run, sandbox, path, options) => this.hydrateLogicalPathForTool(run, sandbox, path, options),
|
|
1884
|
+
recordSandboxTombstone: (run, sandbox, path) => this.recordSandboxTombstone(run, sandbox, path),
|
|
1885
|
+
createCheckpoint: (input) => this.createCheckpoint(input),
|
|
1886
|
+
listHydratedCheckpoints: (runId) => this.listHydratedCheckpoints(runId),
|
|
1887
|
+
emitSpan: (name, startedAt, attributes, options) => this.emitSpan(name, startedAt, attributes, options),
|
|
1888
|
+
runSpanAttributes: (run, extra) => this.runSpanAttributes(run, extra),
|
|
1889
|
+
turnSpanId: (runId) => this.turnSpanId(runId),
|
|
1890
|
+
toolContentAttributes: (input, output) => this.toolContentAttributes(input, output),
|
|
1891
|
+
saveSkill: (input) => this.saveSkill(input),
|
|
1892
|
+
listSkills: () => this.listSkills(),
|
|
1893
|
+
deleteSkill: (name) => this.deleteSkill(name),
|
|
1894
|
+
createDynamicSchedule: (input) => this.createDynamicSchedule(input),
|
|
1895
|
+
listDynamicSchedules: (scope) => this.listDynamicSchedules(scope),
|
|
1896
|
+
updateDynamicSchedule: (scope, id, patch) => this.updateDynamicSchedule(scope, id, patch),
|
|
1897
|
+
deleteDynamicSchedule: (scope, id) => this.deleteDynamicSchedule(scope, id),
|
|
1898
|
+
saveConnectionDefinition: (input) => this.saveConnectionDefinition(input),
|
|
1899
|
+
listConnectionDefinitions: (scope) => this.listConnectionDefinitions(scope),
|
|
1900
|
+
deleteConnectionDefinition: (name, scope) => this.deleteConnectionDefinition(name, scope),
|
|
1901
|
+
listResourcesForRun: (run, scope, input) => this.listResourcesForRun(run, scope, input),
|
|
1902
|
+
readResourceForRun: (run, scope, input) => this.readResourceForRun(run, scope, input),
|
|
1903
|
+
projectResourcesForRun: (run, scope, sandbox, input) => this.projectResourcesForRun(run, scope, sandbox, input)
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
selectTool(options) {
|
|
1907
|
+
return selectToolImpl(this.toolExecutionHost(), options);
|
|
1908
|
+
}
|
|
1909
|
+
async executeTool(run, tool, input, sandboxHandle, approved, idempotencyKey) {
|
|
1910
|
+
return executeToolImpl(this.toolExecutionHost(), run, tool, input, sandboxHandle, approved, idempotencyKey);
|
|
1911
|
+
}
|
|
1912
|
+
async executeToolWithRecord(run, tool, toolCall, input, sandboxHandle, approvedToolCall = false) {
|
|
1913
|
+
return executeToolWithRecordImpl(this.toolExecutionHost(), run, tool, toolCall, input, sandboxHandle, approvedToolCall);
|
|
1914
|
+
}
|
|
1915
|
+
async durableStep(runId, key, fn, options) {
|
|
1916
|
+
return durableStepImpl(this.toolExecutionHost(), runId, key, fn, options);
|
|
1917
|
+
}
|
|
1918
|
+
wrapSandbox(runId, session) {
|
|
1919
|
+
return wrapSandboxImpl(this.toolExecutionHost(), runId, session);
|
|
1920
|
+
}
|
|
1921
|
+
createMemoryToolApi(run) {
|
|
1922
|
+
return createMemoryToolApiImpl(this.toolExecutionHost(), run);
|
|
1923
|
+
}
|
|
1924
|
+
createResourceToolApi(run, sandboxHandle) {
|
|
1925
|
+
return createResourceToolApiImpl(this.toolExecutionHost(), run, sandboxHandle);
|
|
1926
|
+
}
|
|
1927
|
+
resourceProjectionHost() {
|
|
1928
|
+
return {
|
|
1929
|
+
state: this.state,
|
|
1930
|
+
blob: this.blob,
|
|
1931
|
+
memoryStore: this.memoryStore,
|
|
1932
|
+
skillStore: this.skillStore,
|
|
1933
|
+
resourceProjectionPolicy: this.resourceProjectionPolicy,
|
|
1934
|
+
memoryEmbeddingProvider: this.memoryEmbeddingProvider,
|
|
1935
|
+
memoryEmbeddingsEnabled: this.memoryEmbeddingsEnabled,
|
|
1936
|
+
skillScope: () => this.skillScope(),
|
|
1937
|
+
durableAgentScope: () => this.durableAgentScope()
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
async listResourcesForRun(run, scope, input = {}) {
|
|
1941
|
+
return listResourcesForRunImpl(this.resourceProjectionHost(), run, scope, input);
|
|
1942
|
+
}
|
|
1943
|
+
async readResourceForRun(run, scope, input) {
|
|
1944
|
+
return readResourceForRunImpl(this.resourceProjectionHost(), run, scope, input);
|
|
1945
|
+
}
|
|
1946
|
+
async projectResourcesForRun(run, scope, sandbox, input) {
|
|
1947
|
+
return projectResourcesForRunImpl(this.resourceProjectionHost(), run, scope, sandbox, input);
|
|
1948
|
+
}
|
|
1949
|
+
async projectSkillIntoSandbox(run, sandbox, skillName) {
|
|
1950
|
+
return projectSkillIntoSandboxImpl(this.resourceProjectionHost(), run, sandbox, skillName);
|
|
1951
|
+
}
|
|
1952
|
+
async hydrateLogicalPathForTool(run, sandbox, path, options = {}) {
|
|
1953
|
+
return hydrateLogicalPathForToolImpl(this.resourceProjectionHost(), run, sandbox, path, options);
|
|
1954
|
+
}
|
|
1955
|
+
async recordSandboxTombstone(run, sandbox, path) {
|
|
1956
|
+
return recordSandboxTombstoneImpl(this.resourceProjectionHost(), run, sandbox, path);
|
|
1957
|
+
}
|
|
1958
|
+
async readSandboxTombstonesWithMissingProjectedFiles(sandbox) {
|
|
1959
|
+
return readSandboxTombstonesWithMissingProjectedFilesImpl(this.resourceProjectionHost(), sandbox);
|
|
1960
|
+
}
|
|
1961
|
+
memoryScopeForRun(run) {
|
|
1962
|
+
return memoryScopeForRunImpl(this.resourceProjectionHost(), run);
|
|
1963
|
+
}
|
|
1964
|
+
async backfillMemoryDocumentsFromFileIndexes(options = {}) {
|
|
1965
|
+
return backfillMemoryDocumentsFromFileIndexesImpl(this.resourceProjectionHost(), options);
|
|
1966
|
+
}
|
|
1967
|
+
async runMemoryEmbeddingBackfill(options = {}) {
|
|
1968
|
+
return runMemoryEmbeddingBackfillImpl(this.resourceProjectionHost(), options);
|
|
1969
|
+
}
|
|
1970
|
+
hookDispatcher;
|
|
1971
|
+
dispatchHookEvent(runId, event) {
|
|
1972
|
+
if (!this.manifest.hooks?.length)
|
|
1973
|
+
return;
|
|
1974
|
+
this.hookDispatcher ??= createHookDispatcher({
|
|
1975
|
+
agentName: this.agentName(),
|
|
1976
|
+
hooks: this.manifest.hooks,
|
|
1977
|
+
loadModule: (source) => this.sourceLoader.load(source),
|
|
1978
|
+
logger: this.logger
|
|
1979
|
+
});
|
|
1980
|
+
return this.hookDispatcher(runId, event);
|
|
1981
|
+
}
|
|
1982
|
+
/** Per-run capability resolution from `resolvers.ts` (run-resolver.ts). */
|
|
1983
|
+
resolveRunCapabilities(run, options, conversationId) {
|
|
1984
|
+
const input = { runId: run.id, message: options.message };
|
|
1985
|
+
if (options.channel !== undefined)
|
|
1986
|
+
input.channel = options.channel;
|
|
1987
|
+
if (conversationId !== undefined)
|
|
1988
|
+
input.conversationId = conversationId;
|
|
1989
|
+
if (options.metadata !== undefined)
|
|
1990
|
+
input.metadata = options.metadata;
|
|
1991
|
+
return resolveRunCapabilitiesImpl({
|
|
1992
|
+
manifest: this.manifest,
|
|
1993
|
+
env: this.env,
|
|
1994
|
+
loadModule: (source) => this.sourceLoader.load(source),
|
|
1995
|
+
appendEvent: (runId, type, data) => this.state.appendEvent(runId, type, data)
|
|
1996
|
+
}, input);
|
|
1997
|
+
}
|
|
1998
|
+
async loadTool(tool, run) {
|
|
1999
|
+
const stub = resolveEvalToolStub(this.evalStubCursors, run, tool.name) ?? this.toolStubs[tool.name];
|
|
2000
|
+
if (stub) {
|
|
2001
|
+
return {
|
|
2002
|
+
description: tool.description,
|
|
2003
|
+
inputSchema: tool.inputSchema,
|
|
2004
|
+
execute: async (input) => stub(input)
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
// Only builtin-sourced entries resolve to the built-in implementation; an
|
|
2008
|
+
// authored tool that shares a built-in's name is an override and loads its module.
|
|
2009
|
+
if (tool.source.path.startsWith("__builtin__")) {
|
|
2010
|
+
const builtIn = builtInToolDefinition(tool.name);
|
|
2011
|
+
if (builtIn)
|
|
2012
|
+
return builtIn;
|
|
2013
|
+
}
|
|
2014
|
+
const module = await this.sourceLoader.load(tool.source);
|
|
2015
|
+
return module.default;
|
|
2016
|
+
}
|
|
2017
|
+
async loadInstrumentationModule() {
|
|
2018
|
+
if (!this.manifest.instrumentation)
|
|
2019
|
+
return {};
|
|
2020
|
+
return this.sourceLoader.load(this.manifest.instrumentation);
|
|
2021
|
+
}
|
|
2022
|
+
async result(run, response, waitingForApproval, waitingForInput, waitingForConnection) {
|
|
2023
|
+
const result = {
|
|
2024
|
+
run,
|
|
2025
|
+
events: await this.state.listEvents(run.id),
|
|
2026
|
+
toolCalls: await this.state.listToolCalls(run.id),
|
|
2027
|
+
deliveries: await this.state.listDeliveries(run.id),
|
|
2028
|
+
response
|
|
2029
|
+
};
|
|
2030
|
+
if (waitingForApproval !== undefined)
|
|
2031
|
+
result.waitingForApproval = waitingForApproval;
|
|
2032
|
+
if (waitingForInput !== undefined)
|
|
2033
|
+
result.waitingForInput = waitingForInput;
|
|
2034
|
+
if (waitingForConnection !== undefined)
|
|
2035
|
+
result.waitingForConnection = waitingForConnection;
|
|
2036
|
+
return result;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
export async function runLocalAgent(options) {
|
|
2040
|
+
const runtime = new OpenEveRuntime(options);
|
|
2041
|
+
return runtime.run(options);
|
|
2042
|
+
}
|
|
2043
|
+
export function runtimeAdapter(options = {}) {
|
|
2044
|
+
return { kind: "runtime", options };
|
|
2045
|
+
}
|
|
2046
|
+
//# sourceMappingURL=index.js.map
|