@dynamicagents/core 0.9.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 +201 -0
- package/README.md +522 -0
- package/dist/a2a/agent-stub.d.ts +60 -0
- package/dist/a2a/agent-stub.js +1 -0
- package/dist/a2a/caller-token.d.ts +44 -0
- package/dist/a2a/caller-token.js +61 -0
- package/dist/a2a/caller.d.ts +23 -0
- package/dist/a2a/caller.js +33 -0
- package/dist/a2a/card.d.ts +158 -0
- package/dist/a2a/card.js +163 -0
- package/dist/a2a/context.d.ts +19 -0
- package/dist/a2a/context.js +61 -0
- package/dist/a2a/deliver.d.ts +159 -0
- package/dist/a2a/deliver.js +185 -0
- package/dist/a2a/executor.d.ts +84 -0
- package/dist/a2a/executor.js +106 -0
- package/dist/a2a/index.d.ts +35 -0
- package/dist/a2a/index.js +34 -0
- package/dist/a2a/notify.d.ts +106 -0
- package/dist/a2a/notify.js +180 -0
- package/dist/a2a/parts.d.ts +45 -0
- package/dist/a2a/parts.js +94 -0
- package/dist/a2a/push.d.ts +70 -0
- package/dist/a2a/push.js +53 -0
- package/dist/a2a/self-origin.d.ts +91 -0
- package/dist/a2a/self-origin.js +114 -0
- package/dist/a2a/task-store.d.ts +44 -0
- package/dist/a2a/task-store.js +99 -0
- package/dist/a2a/task.d.ts +85 -0
- package/dist/a2a/task.js +15 -0
- package/dist/a2a/verify.d.ts +80 -0
- package/dist/a2a/verify.js +143 -0
- package/dist/agent/budget.d.ts +46 -0
- package/dist/agent/budget.js +42 -0
- package/dist/agent/control.d.ts +109 -0
- package/dist/agent/control.js +115 -0
- package/dist/agent/errors.d.ts +85 -0
- package/dist/agent/errors.js +64 -0
- package/dist/agent/final-reply.d.ts +49 -0
- package/dist/agent/final-reply.js +68 -0
- package/dist/agent/history.d.ts +97 -0
- package/dist/agent/history.js +133 -0
- package/dist/agent/index.d.ts +29 -0
- package/dist/agent/index.js +29 -0
- package/dist/agent/inference.d.ts +110 -0
- package/dist/agent/inference.js +120 -0
- package/dist/agent/model.d.ts +90 -0
- package/dist/agent/model.js +1 -0
- package/dist/agent/session.d.ts +100 -0
- package/dist/agent/session.js +82 -0
- package/dist/agent/workers-ai/index.d.ts +23 -0
- package/dist/agent/workers-ai/index.js +23 -0
- package/dist/agent/workers-ai/runtime.d.ts +42 -0
- package/dist/agent/workers-ai/runtime.js +63 -0
- package/dist/alarm/index.d.ts +77 -0
- package/dist/alarm/index.js +116 -0
- package/dist/config.d.ts +202 -0
- package/dist/config.js +135 -0
- package/dist/contract/index.d.ts +9 -0
- package/dist/contract/index.js +8 -0
- package/dist/contract/plugin.d.ts +324 -0
- package/dist/contract/plugin.js +114 -0
- package/dist/contract/recipe.d.ts +180 -0
- package/dist/contract/recipe.js +1 -0
- package/dist/contract/validation.d.ts +91 -0
- package/dist/contract/validation.js +84 -0
- package/dist/db/db.d.ts +147 -0
- package/dist/db/db.js +90 -0
- package/dist/db/index.d.ts +8 -0
- package/dist/db/index.js +8 -0
- package/dist/db/migrations/index.d.ts +20 -0
- package/dist/db/migrations/index.js +60 -0
- package/dist/db/models/subtasks.d.ts +100 -0
- package/dist/db/models/subtasks.js +241 -0
- package/dist/db/models/tasks.d.ts +118 -0
- package/dist/db/models/tasks.js +274 -0
- package/dist/db/schema.d.ts +468 -0
- package/dist/db/schema.js +88 -0
- package/dist/env.d.ts +53 -0
- package/dist/env.js +47 -0
- package/dist/host/agent.d.ts +305 -0
- package/dist/host/agent.js +400 -0
- package/dist/host/index.d.ts +20 -0
- package/dist/host/index.js +19 -0
- package/dist/host/plugin-host.d.ts +42 -0
- package/dist/host/plugin-host.js +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +17 -0
- package/dist/job/index.d.ts +21 -0
- package/dist/job/index.js +21 -0
- package/dist/job/lifecycle.d.ts +176 -0
- package/dist/job/lifecycle.js +230 -0
- package/dist/job/state.d.ts +92 -0
- package/dist/job/state.js +40 -0
- package/dist/platform.d.ts +138 -0
- package/dist/platform.js +140 -0
- package/dist/round/agent.d.ts +271 -0
- package/dist/round/agent.js +678 -0
- package/dist/round/index.d.ts +25 -0
- package/dist/round/index.js +23 -0
- package/dist/round/policy.d.ts +98 -0
- package/dist/round/policy.js +1 -0
- package/dist/round/subagent.d.ts +87 -0
- package/dist/round/subagent.js +108 -0
- package/dist/round/turn.d.ts +249 -0
- package/dist/round/turn.js +564 -0
- package/dist/round/workflow.d.ts +147 -0
- package/dist/round/workflow.js +387 -0
- package/dist/runtime/index.d.ts +127 -0
- package/dist/runtime/index.js +186 -0
- package/dist/runtime/tool-families.d.ts +32 -0
- package/dist/runtime/tool-families.js +61 -0
- package/dist/subagent/fingerprint.d.ts +37 -0
- package/dist/subagent/fingerprint.js +92 -0
- package/dist/subagent/index.d.ts +169 -0
- package/dist/subagent/index.js +330 -0
- package/dist/subagent/prompt.d.ts +32 -0
- package/dist/subagent/prompt.js +37 -0
- package/dist/subagent/run.d.ts +157 -0
- package/dist/subagent/run.js +540 -0
- package/dist/subagent/workspace.d.ts +85 -0
- package/dist/subagent/workspace.js +127 -0
- package/dist/subtasks/catalog.d.ts +40 -0
- package/dist/subtasks/catalog.js +36 -0
- package/dist/subtasks/decomposition.d.ts +85 -0
- package/dist/subtasks/decomposition.js +156 -0
- package/dist/subtasks/delegate.d.ts +120 -0
- package/dist/subtasks/delegate.js +131 -0
- package/dist/subtasks/index.d.ts +9 -0
- package/dist/subtasks/index.js +9 -0
- package/dist/subtasks/subtask-types.d.ts +91 -0
- package/dist/subtasks/subtask-types.js +103 -0
- package/dist/subtasks/types.d.ts +295 -0
- package/dist/subtasks/types.js +15 -0
- package/dist/testing/auth.d.ts +34 -0
- package/dist/testing/auth.js +35 -0
- package/dist/testing/do.d.ts +29 -0
- package/dist/testing/do.js +25 -0
- package/dist/testing/fake-session.d.ts +26 -0
- package/dist/testing/fake-session.js +37 -0
- package/dist/testing/fixtures.d.ts +64 -0
- package/dist/testing/fixtures.js +104 -0
- package/dist/testing/harness.d.ts +97 -0
- package/dist/testing/harness.js +138 -0
- package/dist/testing/index.d.ts +31 -0
- package/dist/testing/index.js +35 -0
- package/dist/testing/mock-model.d.ts +77 -0
- package/dist/testing/mock-model.js +136 -0
- package/dist/testing/node.d.ts +56 -0
- package/dist/testing/node.js +56 -0
- package/dist/testing/vcr-global-setup.d.ts +12 -0
- package/dist/testing/vcr-global-setup.js +15 -0
- package/dist/testing/vcr-shared.d.ts +38 -0
- package/dist/testing/vcr-shared.js +33 -0
- package/dist/testing/vcr-spec.d.ts +25 -0
- package/dist/testing/vcr-spec.js +124 -0
- package/dist/testing/vcr-store.d.ts +86 -0
- package/dist/testing/vcr-store.js +191 -0
- package/dist/testing/vcr.d.ts +117 -0
- package/dist/testing/vcr.js +275 -0
- package/dist/worker/define-agent.d.ts +123 -0
- package/dist/worker/define-agent.js +20 -0
- package/dist/worker/index.d.ts +218 -0
- package/dist/worker/index.js +369 -0
- package/eslint-rules/index.js +31 -0
- package/eslint-rules/no-deprecated-object-properties.js +81 -0
- package/package.json +178 -0
- package/scripts/generate-keys.mjs +48 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { generateText } from "ai";
|
|
2
|
+
import { Session } from "agents/experimental/memory/session";
|
|
3
|
+
import { createCompactFunction } from "agents/experimental/memory/utils";
|
|
4
|
+
import { sessionText } from "./history.js";
|
|
5
|
+
/**
|
|
6
|
+
* Append a message with a deterministic id exactly once, and return the text that
|
|
7
|
+
* is **durably stored** under that id.
|
|
8
|
+
*
|
|
9
|
+
* `Session.appendMessage` is already idempotent by id: appending an id that
|
|
10
|
+
* exists is a no-op. The read-back is what matters for a re-run step — if it
|
|
11
|
+
* crashed after appending and the retry re-inferred a *different* reply, the
|
|
12
|
+
* append no-ops and this returns the original, durable text. The Session and the
|
|
13
|
+
* value the caller goes on to deliver therefore never disagree.
|
|
14
|
+
*
|
|
15
|
+
* Falls back to the message's own text if the read-back returns null (it cannot,
|
|
16
|
+
* having just been appended) rather than failing a round over a missing echo.
|
|
17
|
+
*/
|
|
18
|
+
export async function appendOnce(session, message) {
|
|
19
|
+
await session.appendMessage(message);
|
|
20
|
+
const stored = await session.getMessage(message.id);
|
|
21
|
+
return stored ? sessionText(stored) : sessionText(message);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Wrap a compaction function so the raw messages it folds into a summary are
|
|
25
|
+
* also handed to `onMessagesDisplaced` before they stop being readable as
|
|
26
|
+
* history. The displaced range is `fromMessageId..toMessageId` of the result,
|
|
27
|
+
* sliced from the `history` the compaction saw.
|
|
28
|
+
*
|
|
29
|
+
* A listener's failure is swallowed — compaction must still shorten history
|
|
30
|
+
* when whatever is listening is briefly unavailable. The alternative is
|
|
31
|
+
* unbounded context because a side concern is down.
|
|
32
|
+
*/
|
|
33
|
+
export function notifyingCompaction(base, onMessagesDisplaced) {
|
|
34
|
+
if (!onMessagesDisplaced)
|
|
35
|
+
return base;
|
|
36
|
+
return async (history, options) => {
|
|
37
|
+
const result = await base(history, options);
|
|
38
|
+
if (result) {
|
|
39
|
+
const from = history.findIndex((m) => m.id === result.fromMessageId);
|
|
40
|
+
const to = history.findIndex((m) => m.id === result.toMessageId);
|
|
41
|
+
if (from !== -1 && to !== -1) {
|
|
42
|
+
try {
|
|
43
|
+
await onMessagesDisplaced(history.slice(from, to + 1));
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
console.error("[session] displacement listener failed", err);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Build the one continuous `Session` an agent Durable Object owns: a read-only
|
|
55
|
+
* `"soul"` identity block + a writable `"memory"` scratchpad, with history
|
|
56
|
+
* compaction summarized by the same model. All of a caller's turns (any channel
|
|
57
|
+
* or thread) accumulate into this single conversation.
|
|
58
|
+
*/
|
|
59
|
+
export function buildAgentSession(agent, model, opts) {
|
|
60
|
+
const compact = notifyingCompaction(createCompactFunction({
|
|
61
|
+
// The one boundary worth owning. `protectHead` (3) and `minTailMessages`
|
|
62
|
+
// (2) keep the SDK defaults: the head is the conversation's opening and is
|
|
63
|
+
// cheap, and the tail floor is a safety net rather than a budget.
|
|
64
|
+
tailTokenBudget: opts.compactTailTokens,
|
|
65
|
+
// Bounded like every other call: an unbounded summary is not the risk, a
|
|
66
|
+
// silently truncated one is — it becomes this caller's memory of everything
|
|
67
|
+
// that scrolled out, with no way to tell it was cut short.
|
|
68
|
+
summarize: (prompt) => generateText({
|
|
69
|
+
model,
|
|
70
|
+
prompt,
|
|
71
|
+
maxOutputTokens: opts.maxOutputTokens
|
|
72
|
+
}).then((r) => r.text)
|
|
73
|
+
}), opts.onMessagesDisplaced);
|
|
74
|
+
return Session.create(agent)
|
|
75
|
+
.withContext("soul", { provider: { get: async () => opts.soul() } })
|
|
76
|
+
.withContext("memory", {
|
|
77
|
+
description: opts.memoryDescription,
|
|
78
|
+
maxTokens: opts.memoryMaxTokens
|
|
79
|
+
})
|
|
80
|
+
.onCompaction(compact)
|
|
81
|
+
.compactAfter(opts.compactAfterTokens);
|
|
82
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workers AI — core's default model provider.
|
|
3
|
+
*
|
|
4
|
+
* A provider rather than a capability: it ships no tools, no prompt copy and no
|
|
5
|
+
* policy; it satisfies {@link file://../model.ts ModelRuntime} and stops.
|
|
6
|
+
*
|
|
7
|
+
* Two things about its shape are worth stating, because both look like
|
|
8
|
+
* omissions:
|
|
9
|
+
*
|
|
10
|
+
* **No `LanguageModel` adapter.** `workers-ai-provider` ships one, so this
|
|
11
|
+
* directory is a factory and nothing else — one file rather than the five a
|
|
12
|
+
* hand-written adapter costs (a prompt mapping, a cache-control policy, an
|
|
13
|
+
* error taxonomy). That is what makes it the cheap default.
|
|
14
|
+
*
|
|
15
|
+
* **No package subpath.** `workers-ai-provider` is a *required* peer and this is
|
|
16
|
+
* the default every un-overridden seam reaches through `DynamicAgent` itself, so
|
|
17
|
+
* it is in every consumer's module graph already and a subpath would buy
|
|
18
|
+
* nothing. It is exported from `@dynamicagents/core/agent` — one symbol, one import
|
|
19
|
+
* path. A provider behind an *optional* peer would want its own subpath instead,
|
|
20
|
+
* so that an agent never calling it does not pay for it; `./anthropic` was one
|
|
21
|
+
* until 0.8.0.
|
|
22
|
+
*/
|
|
23
|
+
export { createWorkersAIModelRuntime, workersAIModels, type WorkersAIRuntimeDeps } from "./runtime.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workers AI — core's default model provider.
|
|
3
|
+
*
|
|
4
|
+
* A provider rather than a capability: it ships no tools, no prompt copy and no
|
|
5
|
+
* policy; it satisfies {@link file://../model.ts ModelRuntime} and stops.
|
|
6
|
+
*
|
|
7
|
+
* Two things about its shape are worth stating, because both look like
|
|
8
|
+
* omissions:
|
|
9
|
+
*
|
|
10
|
+
* **No `LanguageModel` adapter.** `workers-ai-provider` ships one, so this
|
|
11
|
+
* directory is a factory and nothing else — one file rather than the five a
|
|
12
|
+
* hand-written adapter costs (a prompt mapping, a cache-control policy, an
|
|
13
|
+
* error taxonomy). That is what makes it the cheap default.
|
|
14
|
+
*
|
|
15
|
+
* **No package subpath.** `workers-ai-provider` is a *required* peer and this is
|
|
16
|
+
* the default every un-overridden seam reaches through `DynamicAgent` itself, so
|
|
17
|
+
* it is in every consumer's module graph already and a subpath would buy
|
|
18
|
+
* nothing. It is exported from `@dynamicagents/core/agent` — one symbol, one import
|
|
19
|
+
* path. A provider behind an *optional* peer would want its own subpath instead,
|
|
20
|
+
* so that an agent never calling it does not pay for it; `./anthropic` was one
|
|
21
|
+
* until 0.8.0.
|
|
22
|
+
*/
|
|
23
|
+
export { createWorkersAIModelRuntime, workersAIModels } from "./runtime.js";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ModelConfig } from "../../config.js";
|
|
2
|
+
import type { AiEnv } from "../../env.js";
|
|
3
|
+
import type { ModelRuntime, ModelRuntimeFactory } from "../model.js";
|
|
4
|
+
/**
|
|
5
|
+
* The Workers-AI model pair every loop runs on by default, built per agent
|
|
6
|
+
* instance.
|
|
7
|
+
*
|
|
8
|
+
* The predecessor read `env.AI` and five config constants as module-level
|
|
9
|
+
* imports. Neither survives packaging: `env` does not exist at module scope on
|
|
10
|
+
* Workers, and a module constant cannot be overridden by a consumer. So this is
|
|
11
|
+
* a factory over an injected binding and an injected {@link ModelConfig}.
|
|
12
|
+
*/
|
|
13
|
+
export interface WorkersAIRuntimeDeps {
|
|
14
|
+
/** The `AI` binding. Read lazily — see {@link createWorkersAIModelRuntime}. */
|
|
15
|
+
ai: Ai;
|
|
16
|
+
config: ModelConfig;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Build the Workers AI model runtime for one agent instance.
|
|
20
|
+
*
|
|
21
|
+
* The provider is constructed on first *use*, not here. During `wrangler deploy`
|
|
22
|
+
* Cloudflare evaluates module scope to validate the new version, and bindings
|
|
23
|
+
* are not populated at that point — constructing eagerly makes `createWorkersAI`
|
|
24
|
+
* throw "you must provide either a binding or credentials". The same laziness
|
|
25
|
+
* protects a consumer who builds their runtime early.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createWorkersAIModelRuntime(deps: WorkersAIRuntimeDeps): ModelRuntime;
|
|
28
|
+
/**
|
|
29
|
+
* Core's default provider — what every {@link ModelRuntimeFactory} seam lands on
|
|
30
|
+
* when an agent does not override it.
|
|
31
|
+
*
|
|
32
|
+
* One definition rather than one per base class. The body used to be written
|
|
33
|
+
* twice, once in {@link file://../../host/agent.ts DynamicAgent.modelRuntime}
|
|
34
|
+
* and once in
|
|
35
|
+
* {@link file://../../round/subagent.ts RecipeSubagentHost.modelRuntime}, which
|
|
36
|
+
* is the same duplication the seam exists to let a *consumer* avoid.
|
|
37
|
+
*
|
|
38
|
+
* Typed on {@link AiEnv} rather than a caller's full `Env`: a factory that
|
|
39
|
+
* accepts the narrow shape is callable with any env that satisfies it, so both
|
|
40
|
+
* base classes pass `this.env` straight through.
|
|
41
|
+
*/
|
|
42
|
+
export declare const workersAIModels: ModelRuntimeFactory<AiEnv>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createWorkersAI } from "workers-ai-provider";
|
|
2
|
+
/**
|
|
3
|
+
* Build the Workers AI model runtime for one agent instance.
|
|
4
|
+
*
|
|
5
|
+
* The provider is constructed on first *use*, not here. During `wrangler deploy`
|
|
6
|
+
* Cloudflare evaluates module scope to validate the new version, and bindings
|
|
7
|
+
* are not populated at that point — constructing eagerly makes `createWorkersAI`
|
|
8
|
+
* throw "you must provide either a binding or credentials". The same laziness
|
|
9
|
+
* protects a consumer who builds their runtime early.
|
|
10
|
+
*/
|
|
11
|
+
export function createWorkersAIModelRuntime(deps) {
|
|
12
|
+
const { config } = deps;
|
|
13
|
+
let provider;
|
|
14
|
+
const workersai = () => (provider ??= createWorkersAI({
|
|
15
|
+
binding: deps.ai,
|
|
16
|
+
gateway: { id: config.aiGatewayId }
|
|
17
|
+
}));
|
|
18
|
+
/**
|
|
19
|
+
* Per-model Workers-AI settings: pin the AI Gateway id (so per-call metadata does
|
|
20
|
+
* not drop the AI Gateway route), attach correlation metadata when supplied, and
|
|
21
|
+
* set the reasoning budget.
|
|
22
|
+
*
|
|
23
|
+
* Always returns a settings object, even with no metadata: `reasoning_effort`
|
|
24
|
+
* has to reach the binding on every call, and an `undefined` return drops it.
|
|
25
|
+
*/
|
|
26
|
+
const chatSettings = (metadata) => ({
|
|
27
|
+
gateway: { id: config.aiGatewayId, ...(metadata ? { metadata } : {}) },
|
|
28
|
+
reasoning_effort: config.reasoningEffort
|
|
29
|
+
});
|
|
30
|
+
return {
|
|
31
|
+
createModelPair(overrides = {}) {
|
|
32
|
+
const primaryId = overrides.primaryModelId ?? config.chatModelId;
|
|
33
|
+
const fallbackId = overrides.fallbackModelId ?? config.fallbackChatModelId;
|
|
34
|
+
let primary;
|
|
35
|
+
let fallback;
|
|
36
|
+
const settings = chatSettings(overrides.metadata);
|
|
37
|
+
return {
|
|
38
|
+
primary: () => (primary ??= overrides.model ?? workersai()(primaryId, settings)),
|
|
39
|
+
fallback: () => (fallback ??=
|
|
40
|
+
overrides.fallbackModel ??
|
|
41
|
+
overrides.model ??
|
|
42
|
+
workersai()(fallbackId, settings)),
|
|
43
|
+
primaryId: () => primaryId,
|
|
44
|
+
fallbackId: () => fallbackId
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Core's default provider — what every {@link ModelRuntimeFactory} seam lands on
|
|
51
|
+
* when an agent does not override it.
|
|
52
|
+
*
|
|
53
|
+
* One definition rather than one per base class. The body used to be written
|
|
54
|
+
* twice, once in {@link file://../../host/agent.ts DynamicAgent.modelRuntime}
|
|
55
|
+
* and once in
|
|
56
|
+
* {@link file://../../round/subagent.ts RecipeSubagentHost.modelRuntime}, which
|
|
57
|
+
* is the same duplication the seam exists to let a *consumer* avoid.
|
|
58
|
+
*
|
|
59
|
+
* Typed on {@link AiEnv} rather than a caller's full `Env`: a factory that
|
|
60
|
+
* accepts the narrow shape is callable with any env that satisfies it, so both
|
|
61
|
+
* base classes pass `this.env` straight through.
|
|
62
|
+
*/
|
|
63
|
+
export const workersAIModels = (env, config) => createWorkersAIModelRuntime({ ai: env.AI, config });
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dynamicagents/core/alarm` — many deadlines over a Durable Object's one alarm.
|
|
3
|
+
*
|
|
4
|
+
* A Durable Object has exactly **one** alarm, and an object that needs to wake
|
|
5
|
+
* for more than one reason cannot simply call `setAlarm` from each of them: the
|
|
6
|
+
* last writer silently wins, and whatever the loser was waiting on never
|
|
7
|
+
* happens. {@link WakeMap} is the fix — one storage row holding every pending
|
|
8
|
+
* intent, and the only thing in a DO that calls `setAlarm`.
|
|
9
|
+
*
|
|
10
|
+
* **Its own subpath, deliberately.** This is useful to a plain `DurableObject`,
|
|
11
|
+
* not only to a {@link DynamicAgent}, so it must be importable without pulling
|
|
12
|
+
* the agent machinery into a bundle.
|
|
13
|
+
*
|
|
14
|
+
* **Why not `Agent.schedule()`.** The `agents` SDK has the same mechanism, but
|
|
15
|
+
* sells it only as a method on `Agent`: adopting it means the object becomes an
|
|
16
|
+
* `Agent`, whose constructor creates `cf_agents_state`, `cf_agents_mcp_servers`
|
|
17
|
+
* and `cf_agents_queues` in that object's SQLite, builds an `MCPClientManager`,
|
|
18
|
+
* and prototype-patches every public method for tracing. For an object whose
|
|
19
|
+
* SQLite is something else already — a container's filesystem, say — that is a
|
|
20
|
+
* large import for a small one. `agents/schedule` is not an alternative: it is a
|
|
21
|
+
* prompt and a zod schema for parsing natural-language dates, not alarm
|
|
22
|
+
* machinery.
|
|
23
|
+
*
|
|
24
|
+
* This owns *when* an object wakes. What it owes on waking is the object's own:
|
|
25
|
+
* `alarm()` reads {@link WakeMap.due} and dispatches.
|
|
26
|
+
*/
|
|
27
|
+
/** One scheduled wake-up. */
|
|
28
|
+
export interface WakeIntent {
|
|
29
|
+
/** Why we are waking. Namespace it, e.g. `sync-retry:container-shell`. */
|
|
30
|
+
key: string;
|
|
31
|
+
/** Epoch ms at which this intent becomes due. */
|
|
32
|
+
notBefore: number;
|
|
33
|
+
/** Retry counter, for the intents that carry one. */
|
|
34
|
+
attempt?: number;
|
|
35
|
+
}
|
|
36
|
+
/** The single storage row holding every intent. Small, and written atomically. */
|
|
37
|
+
export declare const WAKE_KEY = "wake";
|
|
38
|
+
/** How far out {@link WakeMap.repair} re-arms when the handler itself failed. */
|
|
39
|
+
export declare const WAKE_REPAIR_MS = 60000;
|
|
40
|
+
export declare class WakeMap {
|
|
41
|
+
#private;
|
|
42
|
+
constructor(storage: DurableObjectStorage);
|
|
43
|
+
/**
|
|
44
|
+
* Every pending intent, as a **null-prototype** dictionary rebuilt from own
|
|
45
|
+
* entries only.
|
|
46
|
+
*
|
|
47
|
+
* {@link WakeIntent.key} is a caller-supplied string, so an ordinary object
|
|
48
|
+
* literal would let three of them misbehave: `get("toString")` would return an
|
|
49
|
+
* inherited function rather than `undefined`, `clear("constructor")` would
|
|
50
|
+
* treat a key it never held as present, and `set` on `"__proto__"` would hit
|
|
51
|
+
* `Object.prototype`'s setter and change the prototype instead of storing the
|
|
52
|
+
* intent. With no prototype there is nothing to inherit and nothing to poison,
|
|
53
|
+
* and every string round-trips as an ordinary key.
|
|
54
|
+
*/
|
|
55
|
+
all(): Promise<Record<string, WakeIntent>>;
|
|
56
|
+
get(key: string): Promise<WakeIntent | undefined>;
|
|
57
|
+
set(intent: WakeIntent): Promise<void>;
|
|
58
|
+
clear(key: string): Promise<void>;
|
|
59
|
+
/** Every intent whose time has come, earliest first. */
|
|
60
|
+
due(now: number): Promise<WakeIntent[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Point the alarm at the earliest deadline.
|
|
63
|
+
*
|
|
64
|
+
* Only ever moved **earlier**, never later: an alarm that fires too soon finds
|
|
65
|
+
* nothing due, re-arms, and costs one wake-up, whereas an alarm pushed later
|
|
66
|
+
* by a coincidental write silently delays whatever was already waiting. When
|
|
67
|
+
* no intents remain the alarm is deleted outright, so an idle object does not
|
|
68
|
+
* wake on a schedule it has no use for.
|
|
69
|
+
*/
|
|
70
|
+
rearm(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Re-arm shortly, for when the handler failed before it could work out what
|
|
73
|
+
* it owed. Distinct from {@link rearm} because that one trusts the map, and
|
|
74
|
+
* the map is what we just failed to read.
|
|
75
|
+
*/
|
|
76
|
+
repair(now: number): Promise<void>;
|
|
77
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dynamicagents/core/alarm` — many deadlines over a Durable Object's one alarm.
|
|
3
|
+
*
|
|
4
|
+
* A Durable Object has exactly **one** alarm, and an object that needs to wake
|
|
5
|
+
* for more than one reason cannot simply call `setAlarm` from each of them: the
|
|
6
|
+
* last writer silently wins, and whatever the loser was waiting on never
|
|
7
|
+
* happens. {@link WakeMap} is the fix — one storage row holding every pending
|
|
8
|
+
* intent, and the only thing in a DO that calls `setAlarm`.
|
|
9
|
+
*
|
|
10
|
+
* **Its own subpath, deliberately.** This is useful to a plain `DurableObject`,
|
|
11
|
+
* not only to a {@link DynamicAgent}, so it must be importable without pulling
|
|
12
|
+
* the agent machinery into a bundle.
|
|
13
|
+
*
|
|
14
|
+
* **Why not `Agent.schedule()`.** The `agents` SDK has the same mechanism, but
|
|
15
|
+
* sells it only as a method on `Agent`: adopting it means the object becomes an
|
|
16
|
+
* `Agent`, whose constructor creates `cf_agents_state`, `cf_agents_mcp_servers`
|
|
17
|
+
* and `cf_agents_queues` in that object's SQLite, builds an `MCPClientManager`,
|
|
18
|
+
* and prototype-patches every public method for tracing. For an object whose
|
|
19
|
+
* SQLite is something else already — a container's filesystem, say — that is a
|
|
20
|
+
* large import for a small one. `agents/schedule` is not an alternative: it is a
|
|
21
|
+
* prompt and a zod schema for parsing natural-language dates, not alarm
|
|
22
|
+
* machinery.
|
|
23
|
+
*
|
|
24
|
+
* This owns *when* an object wakes. What it owes on waking is the object's own:
|
|
25
|
+
* `alarm()` reads {@link WakeMap.due} and dispatches.
|
|
26
|
+
*/
|
|
27
|
+
/** The single storage row holding every intent. Small, and written atomically. */
|
|
28
|
+
export const WAKE_KEY = "wake";
|
|
29
|
+
/** How far out {@link WakeMap.repair} re-arms when the handler itself failed. */
|
|
30
|
+
export const WAKE_REPAIR_MS = 60_000;
|
|
31
|
+
export class WakeMap {
|
|
32
|
+
#storage;
|
|
33
|
+
constructor(storage) {
|
|
34
|
+
this.#storage = storage;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Every pending intent, as a **null-prototype** dictionary rebuilt from own
|
|
38
|
+
* entries only.
|
|
39
|
+
*
|
|
40
|
+
* {@link WakeIntent.key} is a caller-supplied string, so an ordinary object
|
|
41
|
+
* literal would let three of them misbehave: `get("toString")` would return an
|
|
42
|
+
* inherited function rather than `undefined`, `clear("constructor")` would
|
|
43
|
+
* treat a key it never held as present, and `set` on `"__proto__"` would hit
|
|
44
|
+
* `Object.prototype`'s setter and change the prototype instead of storing the
|
|
45
|
+
* intent. With no prototype there is nothing to inherit and nothing to poison,
|
|
46
|
+
* and every string round-trips as an ordinary key.
|
|
47
|
+
*/
|
|
48
|
+
async all() {
|
|
49
|
+
const stored = await this.#storage.get(WAKE_KEY);
|
|
50
|
+
const intents = Object.create(null);
|
|
51
|
+
// `Object.entries` is own-enumerable-only, so nothing from a prototype can
|
|
52
|
+
// enter here even if the stored value arrived with one.
|
|
53
|
+
if (stored) {
|
|
54
|
+
for (const [key, intent] of Object.entries(stored))
|
|
55
|
+
intents[key] = intent;
|
|
56
|
+
}
|
|
57
|
+
return intents;
|
|
58
|
+
}
|
|
59
|
+
async get(key) {
|
|
60
|
+
return (await this.all())[key];
|
|
61
|
+
}
|
|
62
|
+
async set(intent) {
|
|
63
|
+
const all = await this.all();
|
|
64
|
+
all[intent.key] = intent;
|
|
65
|
+
await this.#storage.put(WAKE_KEY, all);
|
|
66
|
+
await this.rearm();
|
|
67
|
+
}
|
|
68
|
+
async clear(key) {
|
|
69
|
+
const all = await this.all();
|
|
70
|
+
// `hasOwn`, not `in`: the dictionary has no prototype today, and this stays
|
|
71
|
+
// correct if that ever changes.
|
|
72
|
+
if (!Object.hasOwn(all, key))
|
|
73
|
+
return;
|
|
74
|
+
delete all[key];
|
|
75
|
+
await this.#storage.put(WAKE_KEY, all);
|
|
76
|
+
await this.rearm();
|
|
77
|
+
}
|
|
78
|
+
/** Every intent whose time has come, earliest first. */
|
|
79
|
+
async due(now) {
|
|
80
|
+
return Object.values(await this.all())
|
|
81
|
+
.filter((intent) => intent.notBefore <= now)
|
|
82
|
+
.sort((a, b) => a.notBefore - b.notBefore);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Point the alarm at the earliest deadline.
|
|
86
|
+
*
|
|
87
|
+
* Only ever moved **earlier**, never later: an alarm that fires too soon finds
|
|
88
|
+
* nothing due, re-arms, and costs one wake-up, whereas an alarm pushed later
|
|
89
|
+
* by a coincidental write silently delays whatever was already waiting. When
|
|
90
|
+
* no intents remain the alarm is deleted outright, so an idle object does not
|
|
91
|
+
* wake on a schedule it has no use for.
|
|
92
|
+
*/
|
|
93
|
+
async rearm() {
|
|
94
|
+
const deadlines = Object.values(await this.all()).map((i) => i.notBefore);
|
|
95
|
+
const existing = await this.#storage.getAlarm();
|
|
96
|
+
if (deadlines.length === 0) {
|
|
97
|
+
if (existing !== null)
|
|
98
|
+
await this.#storage.deleteAlarm();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const earliest = Math.min(...deadlines);
|
|
102
|
+
if (existing === null || existing > earliest) {
|
|
103
|
+
await this.#storage.setAlarm(earliest);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Re-arm shortly, for when the handler failed before it could work out what
|
|
108
|
+
* it owed. Distinct from {@link rearm} because that one trusts the map, and
|
|
109
|
+
* the map is what we just failed to read.
|
|
110
|
+
*/
|
|
111
|
+
async repair(now) {
|
|
112
|
+
const existing = await this.#storage.getAlarm();
|
|
113
|
+
if (existing === null)
|
|
114
|
+
await this.#storage.setAlarm(now + WAKE_REPAIR_MS);
|
|
115
|
+
}
|
|
116
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/** Model ids and per-call generation settings. */
|
|
2
|
+
export interface ModelConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Workers AI model for the tool loop. Must support function calling.
|
|
5
|
+
*
|
|
6
|
+
* **Required — core ships no default.** Which model an agent runs on is the
|
|
7
|
+
* single most consequential thing about it: it sets the cost of every turn,
|
|
8
|
+
* the tool-calling reliability the whole control-tool design rests on, and the
|
|
9
|
+
* failure modes the fallback exists to escape. A default here would be core
|
|
10
|
+
* making that choice on a consumer's behalf, silently, and being wrong for
|
|
11
|
+
* most of them — the same reason core ships no prompt copy.
|
|
12
|
+
*
|
|
13
|
+
* It is also the value most likely to age badly. A model id baked into a
|
|
14
|
+
* published package survives every deprecation until someone bumps the
|
|
15
|
+
* package; one written in the agent that uses it is read by whoever owns the
|
|
16
|
+
* bill.
|
|
17
|
+
*/
|
|
18
|
+
chatModelId: string;
|
|
19
|
+
/**
|
|
20
|
+
* Tried when the primary throws. **Required — core ships no default.**
|
|
21
|
+
*
|
|
22
|
+
* Should be a *different vendor and family* — a same-family fallback shares
|
|
23
|
+
* the failure mode you are falling back from, which makes it a retry wearing
|
|
24
|
+
* a costume. Core cannot pick this for you precisely because it depends on
|
|
25
|
+
* what you chose as primary.
|
|
26
|
+
*/
|
|
27
|
+
fallbackChatModelId: string;
|
|
28
|
+
/** AI Gateway slug; `"default"` auto-provisions on first request. */
|
|
29
|
+
aiGatewayId: string;
|
|
30
|
+
/**
|
|
31
|
+
* Output-token ceiling for every chat call. Left unset, the binding applies a
|
|
32
|
+
* per-model default which a reasoning model spends on `reasoning_content`
|
|
33
|
+
* before emitting the tool call — a truncated round that reads as a clean
|
|
34
|
+
* answer. Generous on purpose: it bounds a runaway, it does not ration.
|
|
35
|
+
*/
|
|
36
|
+
maxOutputTokens: number;
|
|
37
|
+
/** Reasoning budget forwarded on the binding's `inputs` by workers-ai-provider. */
|
|
38
|
+
reasoningEffort: "low" | "medium" | "high";
|
|
39
|
+
/**
|
|
40
|
+
* How many times a single model call is retried **on the same model** before
|
|
41
|
+
* the round gives up on that slot and moves to the fallback.
|
|
42
|
+
*
|
|
43
|
+
* This was hardcoded to `0` for a long time, with a reason that was right for
|
|
44
|
+
* one case and wrong for the other. The reason: primary→fallback recovery is
|
|
45
|
+
* ours, so provider-level backoff only adds latency and duplicates it. True
|
|
46
|
+
* when the two slots are different vendors, which is what
|
|
47
|
+
* {@link fallbackChatModelId} advises — a 429 on one says nothing about the
|
|
48
|
+
* other, so falling straight through is the fastest correct move.
|
|
49
|
+
*
|
|
50
|
+
* It is false for a rate limit on an agent whose slots share a credential. A
|
|
51
|
+
* coder running Opus with Sonnet as its step-down burns the fallback proving
|
|
52
|
+
* the same 429 twice, then throws, then the Workflow retries the whole round
|
|
53
|
+
* and does it again. Waiting the `retry-after` the provider actually sent is
|
|
54
|
+
* both cheaper and far more likely to work.
|
|
55
|
+
*
|
|
56
|
+
* The AI SDK does the waiting, and it does it properly:
|
|
57
|
+
* `retryWithExponentialBackoffRespectingRetryHeaders` honours `retry-after-ms`
|
|
58
|
+
* and `retry-after` and falls back to exponential backoff. It only fires for
|
|
59
|
+
* an `APICallError` carrying `isRetryable`, so a provider written outside core
|
|
60
|
+
* has to map its errors into that shape rather than rethrowing them raw, or
|
|
61
|
+
* none of this fires for it.
|
|
62
|
+
*
|
|
63
|
+
* Bounded at 4 by `resolveConfig`. The retries happen *inside*
|
|
64
|
+
* `step.do("turn:<round>")`, and the SDK caps a single honoured `retry-after`
|
|
65
|
+
* at 60s, so the worst case is roughly `maxRetries` minutes of waiting before
|
|
66
|
+
* the round has spent a token of its own — against
|
|
67
|
+
* {@link file://./platform.ts STEP_TIMEOUT_MS}, which is where that ceiling is
|
|
68
|
+
* stated and the only place it should be read from.
|
|
69
|
+
*/
|
|
70
|
+
maxRetries: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* An execution budget, in the only two currencies that mean anything: **turns**
|
|
74
|
+
* (what it costs) and **wall clock** (how long it can run away for).
|
|
75
|
+
*
|
|
76
|
+
* Rounds, chunks and steps are *mechanics*, not budgets — a round is the
|
|
77
|
+
* delegate/answer loop, a chunk is a durable slice sized by the Workers step
|
|
78
|
+
* timeout. None of them is tunable and none belongs here. Conflating the two is
|
|
79
|
+
* what once made an overnight runaway look healthy to every cap in the system.
|
|
80
|
+
*
|
|
81
|
+
* Reaching either ceiling does the same thing at either level: one final call
|
|
82
|
+
* with **no tools** — "you have spent your budget, answer now from what you
|
|
83
|
+
* have". A ceiling yields an answer; it never drops the work.
|
|
84
|
+
*/
|
|
85
|
+
export interface AgentLimits {
|
|
86
|
+
/**
|
|
87
|
+
* Tool-loop steps, summed across every round *and* across the
|
|
88
|
+
* primary→fallback attempt within a round — a fallback attempt is real spend.
|
|
89
|
+
*/
|
|
90
|
+
maxTurns: number;
|
|
91
|
+
/**
|
|
92
|
+
* Measured from the first durable step. Note for whoever implements
|
|
93
|
+
* escalation: this must be **rebased** after a `step.waitForEvent(...)`
|
|
94
|
+
* returns, or a human's thinking time is charged to the agent and a task that
|
|
95
|
+
* asks a question at minute 5 is dead before the answer arrives. Turns need no
|
|
96
|
+
* such care — waiting costs none.
|
|
97
|
+
*/
|
|
98
|
+
maxWallMs: number;
|
|
99
|
+
}
|
|
100
|
+
/** Session memory + compaction tuning. */
|
|
101
|
+
export interface SessionConfig {
|
|
102
|
+
/** Soft cap (tokens) for the self-edited `"memory"` scratchpad block. */
|
|
103
|
+
memoryMaxTokens: number;
|
|
104
|
+
/** Live-history token threshold that triggers automatic compaction. */
|
|
105
|
+
compactAfterTokens: number;
|
|
106
|
+
/**
|
|
107
|
+
* Tokens of the most recent history compaction keeps **verbatim**.
|
|
108
|
+
*
|
|
109
|
+
* Read this together with {@link compactAfterTokens}; neither means anything
|
|
110
|
+
* alone. After a compaction the floor is `system + protectHead + summary +
|
|
111
|
+
* tail`, so the conversation that must accumulate before compaction fires
|
|
112
|
+
* again is `Δ = compactAfterTokens − floor`, and the SDK sizes each summary at
|
|
113
|
+
* 20% of the middle it folded, so at equilibrium `S ≈ 0.2Δ`.
|
|
114
|
+
*
|
|
115
|
+
* INVARIANT: `compactAfterTokens − compactTailTokens >= 10_000`, asserted in
|
|
116
|
+
* `session.spec.ts`. Below it the fixed floor eats the gap and compaction
|
|
117
|
+
* fires on nearly every append, each firing spending a summarizer call on a
|
|
118
|
+
* near-empty middle. Never lower the threshold without lowering the tail too.
|
|
119
|
+
*/
|
|
120
|
+
compactTailTokens: number;
|
|
121
|
+
/** One-line description shown to the model for the writable `"memory"` block. */
|
|
122
|
+
memoryDescription: string;
|
|
123
|
+
}
|
|
124
|
+
export interface CoreConfig {
|
|
125
|
+
model: ModelConfig;
|
|
126
|
+
/** What bounds the MAIN agent across every round of one task. */
|
|
127
|
+
mainAgentLimits: AgentLimits;
|
|
128
|
+
/**
|
|
129
|
+
* The baseline every subagent branch runs under. A recipe may override either
|
|
130
|
+
* field — to any positive integer, larger included — and inherits the baseline
|
|
131
|
+
* for whatever it does not validly declare. A default, not a ceiling.
|
|
132
|
+
*/
|
|
133
|
+
subagentLimits: AgentLimits;
|
|
134
|
+
/**
|
|
135
|
+
* How many of the most recent assistant turns keep their tool **results** in a
|
|
136
|
+
* subagent's rolling window. Older results are stubbed; the tool *calls* and
|
|
137
|
+
* the model's own text always survive the full `historyWindow`, because that
|
|
138
|
+
* is where a recipe's model keeps whatever it wrote down for itself.
|
|
139
|
+
*
|
|
140
|
+
* A mechanic of the window, not a property of a domain — which is why it is
|
|
141
|
+
* deliberately not a recipe field: recipe fields are fingerprinted, and
|
|
142
|
+
* changing a fingerprint strands every in-flight run behind a mismatch that
|
|
143
|
+
* costs it its whole history.
|
|
144
|
+
*/
|
|
145
|
+
toolOutputWindow: number;
|
|
146
|
+
/**
|
|
147
|
+
* Upper bound on subtasks per **round** — a core invariant: a delegating round
|
|
148
|
+
* emits `1..maxSubtasks` subtasks, which is also what bounds its fan-out (they
|
|
149
|
+
* all run concurrently, with no other concurrency cap).
|
|
150
|
+
*
|
|
151
|
+
* Not a budget but a shape: it is what the delegation schema offers the model,
|
|
152
|
+
* and the data layer re-checks it as the durable guard.
|
|
153
|
+
*/
|
|
154
|
+
maxSubtasks: number;
|
|
155
|
+
session: SessionConfig;
|
|
156
|
+
}
|
|
157
|
+
/** The two ids an agent must choose for itself. Core has no opinion. */
|
|
158
|
+
export type RequiredModelIds = Pick<ModelConfig, "chatModelId" | "fallbackChatModelId">;
|
|
159
|
+
/**
|
|
160
|
+
* The baseline, which is everything core *does* still have an opinion about.
|
|
161
|
+
*
|
|
162
|
+
* Note what is missing: the model pair. This type is `CoreConfig` minus those
|
|
163
|
+
* two ids precisely so that no value of it can supply them — a default nobody
|
|
164
|
+
* declared is how an agent ends up billing a model its author never chose.
|
|
165
|
+
*/
|
|
166
|
+
export type CoreConfigBaseline = Omit<CoreConfig, "model"> & {
|
|
167
|
+
model: Omit<ModelConfig, keyof RequiredModelIds>;
|
|
168
|
+
};
|
|
169
|
+
/**
|
|
170
|
+
* A working baseline. Every value is overridable; none is a ceiling. These are
|
|
171
|
+
* the values both predecessor agents converged on in production, so they are a
|
|
172
|
+
* reasonable place to start rather than an opinion about your domain.
|
|
173
|
+
*
|
|
174
|
+
* **It carries no model ids.** See {@link ModelConfig.chatModelId}.
|
|
175
|
+
*/
|
|
176
|
+
export declare const DEFAULT_CORE_CONFIG: CoreConfigBaseline;
|
|
177
|
+
/**
|
|
178
|
+
* One level of optionality per nested group — enough for a config this shallow.
|
|
179
|
+
*
|
|
180
|
+
* `model` is the exception, and deliberately not optional: an agent must name
|
|
181
|
+
* its own primary and fallback. That is a compile error rather than a runtime
|
|
182
|
+
* one, so the omission is found while writing the agent rather than on the first
|
|
183
|
+
* request it serves.
|
|
184
|
+
*/
|
|
185
|
+
export type CoreConfigOverrides = {
|
|
186
|
+
[K in Exclude<keyof CoreConfig, "model">]?: CoreConfig[K] extends object ? Partial<CoreConfig[K]> : CoreConfig[K];
|
|
187
|
+
} & {
|
|
188
|
+
/** Required: the two model ids, plus any generation setting you want changed. */
|
|
189
|
+
model: RequiredModelIds & Partial<Omit<ModelConfig, keyof RequiredModelIds>>;
|
|
190
|
+
};
|
|
191
|
+
export declare class ConfigError extends Error {
|
|
192
|
+
constructor(message: string);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Merge overrides onto {@link DEFAULT_CORE_CONFIG} and check the invariants that
|
|
196
|
+
* are cheap to get wrong and expensive to notice.
|
|
197
|
+
*
|
|
198
|
+
* Called once, at DO start, and the result threaded explicitly from there. Do
|
|
199
|
+
* not call it per-request: the point of resolving is that every module downstream
|
|
200
|
+
* reads the same object.
|
|
201
|
+
*/
|
|
202
|
+
export declare function resolveConfig(overrides: CoreConfigOverrides): CoreConfig;
|