@leuduan/lagent 0.0.0-stage → 0.1.2
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 +16 -0
- package/README.md +144 -2
- package/dist/chunks/2O7ZGEIT.js +1 -0
- package/dist/chunks/2OSESBIL.js +1 -0
- package/dist/chunks/34KW6VNQ.js +1 -0
- package/dist/chunks/37YOGDGY.js +1 -0
- package/dist/chunks/3LQHQRIU.js +6 -0
- package/dist/chunks/3QCW4WDJ.js +1 -0
- package/dist/chunks/4XVRUSCQ.js +1 -0
- package/dist/chunks/6ECI2GGV.js +1 -0
- package/dist/chunks/74HKUGRR.js +1 -0
- package/dist/chunks/ADHERZLW.js +2 -0
- package/dist/chunks/AP6Q4EPT.js +36 -0
- package/dist/chunks/BM3S37EZ.js +1 -0
- package/dist/chunks/C5LYCXJG.js +1 -0
- package/dist/chunks/CDQG7RKA.js +1 -0
- package/dist/chunks/D7E6EWIE.js +3 -0
- package/dist/chunks/DDANMY45.js +3 -0
- package/dist/chunks/DRYAN665.js +1 -0
- package/dist/chunks/DXFXAYDN.js +17 -0
- package/dist/chunks/EGZI4XQX.js +24 -0
- package/dist/chunks/ENWFSU27.js +41 -0
- package/dist/chunks/G6RXC3AL.js +1 -0
- package/dist/chunks/G74AGRAJ.js +15 -0
- package/dist/chunks/GQGNVSKB.js +1 -0
- package/dist/chunks/IJ2WNMD5.js +7 -0
- package/dist/chunks/J5S4URAW.js +1 -0
- package/dist/chunks/JPZFKSWT.js +1 -0
- package/dist/chunks/KESCTXGO.js +5 -0
- package/dist/chunks/L3N4FIEN.js +1 -0
- package/dist/chunks/NAOUTU7A.js +4 -0
- package/dist/chunks/NDIM7MEW.js +1 -0
- package/dist/chunks/O4PPOM5Z.js +2 -0
- package/dist/chunks/OVZFGILJ.js +1 -0
- package/dist/chunks/P5ZHHOOM.js +6 -0
- package/dist/chunks/PUSUPTAT.js +1 -0
- package/dist/chunks/QMMLQJBS.js +1 -0
- package/dist/chunks/RK3VP2Q4.js +3 -0
- package/dist/chunks/SGGMBSBA.js +1 -0
- package/dist/chunks/SL2YLB2F.js +1 -0
- package/dist/chunks/TOOIB6J2.js +1 -0
- package/dist/chunks/TYTQRLTX.js +1 -0
- package/dist/chunks/UC3FVVJ2.js +5 -0
- package/dist/chunks/UCTEU62F.js +1 -0
- package/dist/chunks/UD3VJER6.js +1 -0
- package/dist/chunks/UKXMCHHT.js +1 -0
- package/dist/chunks/WUUKTSRT.js +7 -0
- package/dist/chunks/X65X4KP5.js +7 -0
- package/dist/chunks/YIR5MYGU.js +1 -0
- package/dist/chunks/YLNJXQ3Z.js +1 -0
- package/dist/context.d.ts +101 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +77 -0
- package/dist/journal/catalog.d.ts +112 -0
- package/dist/journal/forkChain.d.ts +16 -0
- package/dist/journal/index.d.ts +15 -0
- package/dist/journal/journal.d.ts +475 -0
- package/dist/journal/projection.d.ts +87 -0
- package/dist/journal/store.d.ts +181 -0
- package/dist/kit/claim.d.ts +13 -0
- package/dist/kit/drain.d.ts +10 -0
- package/dist/kit/extension.d.ts +180 -0
- package/dist/kit/grants.d.ts +9 -0
- package/dist/kit/modes.d.ts +65 -0
- package/dist/kit/retries.d.ts +25 -0
- package/dist/kit/scope.d.ts +32 -0
- package/dist/kit/service.d.ts +7 -0
- package/dist/kit/strategy.d.ts +10 -0
- package/dist/kit/timers.d.ts +43 -0
- package/dist/kit/tool.d.ts +72 -0
- package/dist/llm/client.d.ts +135 -0
- package/dist/llm/content.d.ts +52 -0
- package/dist/llm/door.d.ts +21 -0
- package/dist/llm/door.js +1 -0
- package/dist/llm/failure.d.ts +82 -0
- package/dist/llm/index.d.ts +16 -0
- package/dist/llm/primitives.d.ts +286 -0
- package/dist/llm/prompt.d.ts +21 -0
- package/dist/llm/provider.d.ts +63 -0
- package/dist/llm/readLedger.d.ts +24 -0
- package/dist/llm/request.d.ts +58 -0
- package/dist/loop/agent.d.ts +134 -0
- package/dist/loop/auxiliary.d.ts +54 -0
- package/dist/loop/chain.d.ts +46 -0
- package/dist/loop/chunks.d.ts +27 -0
- package/dist/loop/continuation.d.ts +166 -0
- package/dist/loop/decide.d.ts +64 -0
- package/dist/loop/errors.d.ts +162 -0
- package/dist/loop/forks.d.ts +61 -0
- package/dist/loop/holds.d.ts +104 -0
- package/dist/loop/hooks.d.ts +241 -0
- package/dist/loop/inbox.d.ts +188 -0
- package/dist/loop/index.d.ts +37 -0
- package/dist/loop/limits.d.ts +14 -0
- package/dist/loop/opening.d.ts +42 -0
- package/dist/loop/prepare.d.ts +30 -0
- package/dist/loop/projections.d.ts +307 -0
- package/dist/loop/replace.d.ts +33 -0
- package/dist/loop/requests.d.ts +129 -0
- package/dist/loop/route.d.ts +53 -0
- package/dist/loop/runtime.d.ts +85 -0
- package/dist/loop/state.d.ts +70 -0
- package/dist/loop/strategy.d.ts +71 -0
- package/dist/loop/summary.d.ts +3 -0
- package/dist/loop/surface.d.ts +153 -0
- package/dist/loop/threadState.d.ts +72 -0
- package/dist/loop/tool.d.ts +101 -0
- package/dist/loop/toolCalls.d.ts +42 -0
- package/dist/loop/wake.d.ts +32 -0
- package/dist/models/config/agent.d.ts +18 -0
- package/dist/models/config/prompt.d.ts +18 -0
- package/dist/models/door.d.ts +12 -0
- package/dist/models/door.js +1 -0
- package/dist/models/index.d.ts +7 -0
- package/dist/models/jsonSchema.d.ts +7 -0
- package/dist/models/wire/journal.d.ts +2772 -0
- package/dist/models/wire/primitives.d.ts +65 -0
- package/dist/plugin.d.ts +53 -0
- package/dist/plugin.js +1 -0
- package/dist/plugins/agentsMd.d.ts +76 -0
- package/dist/plugins/agentsMd.js +1 -0
- package/dist/plugins/ask/askQuestion.d.ts +9 -0
- package/dist/plugins/ask/index.d.ts +26 -0
- package/dist/plugins/ask/index.js +1 -0
- package/dist/plugins/ask/service.d.ts +125 -0
- package/dist/plugins/commands/background.d.ts +8 -0
- package/dist/plugins/commands/foreground.d.ts +4 -0
- package/dist/plugins/commands/index.d.ts +40 -0
- package/dist/plugins/commands/index.js +1 -0
- package/dist/plugins/commands/output.d.ts +115 -0
- package/dist/plugins/commands/record.d.ts +549 -0
- package/dist/plugins/commands/service.d.ts +314 -0
- package/dist/plugins/commands/shell.d.ts +25 -0
- package/dist/plugins/compaction/checkpoint.d.ts +91 -0
- package/dist/plugins/compaction/config.d.ts +133 -0
- package/dist/plugins/compaction/estimate.d.ts +29 -0
- package/dist/plugins/compaction/index.d.ts +2 -0
- package/dist/plugins/compaction/index.js +7 -0
- package/dist/plugins/compaction/log.d.ts +61 -0
- package/dist/plugins/compaction/planner.d.ts +207 -0
- package/dist/plugins/compaction/preset.d.ts +86 -0
- package/dist/plugins/compaction/prune.d.ts +9 -0
- package/dist/plugins/compaction/records.d.ts +227 -0
- package/dist/plugins/compaction/segments.d.ts +23 -0
- package/dist/plugins/compaction/shared.d.ts +14 -0
- package/dist/plugins/compaction/summarize.d.ts +13 -0
- package/dist/plugins/dateAndBranch.d.ts +47 -0
- package/dist/plugins/dateAndBranch.js +1 -0
- package/dist/plugins/delegations/answers.d.ts +39 -0
- package/dist/plugins/delegations/assignmentKey.d.ts +22 -0
- package/dist/plugins/delegations/cleanup.d.ts +161 -0
- package/dist/plugins/delegations/constraint.d.ts +76 -0
- package/dist/plugins/delegations/index.d.ts +39 -0
- package/dist/plugins/delegations/index.js +1 -0
- package/dist/plugins/delegations/notices.d.ts +261 -0
- package/dist/plugins/delegations/obligations.d.ts +210 -0
- package/dist/plugins/delegations/record.d.ts +632 -0
- package/dist/plugins/delegations/request.d.ts +381 -0
- package/dist/plugins/delegations/role.d.ts +30 -0
- package/dist/plugins/delegations/service.d.ts +562 -0
- package/dist/plugins/delegations/standing.d.ts +19 -0
- package/dist/plugins/delegations/stopCheck.d.ts +21 -0
- package/dist/plugins/delegations/testing.d.ts +16 -0
- package/dist/plugins/delegations/tools.d.ts +71 -0
- package/dist/plugins/delegations/waitBook.d.ts +116 -0
- package/dist/plugins/delegations/waits.d.ts +118 -0
- package/dist/plugins/diagnostics/digest.d.ts +14 -0
- package/dist/plugins/diagnostics/index.d.ts +68 -0
- package/dist/plugins/diagnostics/index.js +1 -0
- package/dist/plugins/historyRecall/history.d.ts +9 -0
- package/dist/plugins/historyRecall/index.d.ts +31 -0
- package/dist/plugins/historyRecall/index.js +1 -0
- package/dist/plugins/historyRecall/render.d.ts +34 -0
- package/dist/plugins/historyRecall/tools.d.ts +4 -0
- package/dist/plugins/mcp/catalog.d.ts +36 -0
- package/dist/plugins/mcp/config.d.ts +63 -0
- package/dist/plugins/mcp/connection.d.ts +53 -0
- package/dist/plugins/mcp/errors.d.ts +32 -0
- package/dist/plugins/mcp/index.d.ts +33 -0
- package/dist/plugins/mcp/index.js +5 -0
- package/dist/plugins/mcp/mount.d.ts +98 -0
- package/dist/plugins/mcp/names.d.ts +25 -0
- package/dist/plugins/mcp/render.d.ts +29 -0
- package/dist/plugins/mcp/slots.d.ts +15 -0
- package/dist/plugins/mcp/stdio.d.ts +49 -0
- package/dist/plugins/mcp/tool.d.ts +41 -0
- package/dist/plugins/providers/anthropic.d.ts +175 -0
- package/dist/plugins/providers/anthropicMessages.d.ts +65 -0
- package/dist/plugins/providers/codex.d.ts +60 -0
- package/dist/plugins/providers/codexAuth.d.ts +116 -0
- package/dist/plugins/providers/deepseek.d.ts +55 -0
- package/dist/plugins/providers/door.d.ts +61 -0
- package/dist/plugins/providers/door.js +1 -0
- package/dist/plugins/providers/failure.d.ts +23 -0
- package/dist/plugins/providers/gateway.d.ts +23 -0
- package/dist/plugins/providers/index.d.ts +6 -0
- package/dist/plugins/providers/openaiChat.d.ts +62 -0
- package/dist/plugins/providers/openaiResponses.d.ts +100 -0
- package/dist/plugins/providers/opencodeCopilot.d.ts +23 -0
- package/dist/plugins/providers/opencodeGo.d.ts +98 -0
- package/dist/plugins/providers/shared.d.ts +104 -0
- package/dist/plugins/providers/stream.d.ts +154 -0
- package/dist/plugins/routeContext.d.ts +22 -0
- package/dist/plugins/routeContext.js +1 -0
- package/dist/plugins/schedules/index.d.ts +21 -0
- package/dist/plugins/schedules/index.js +5 -0
- package/dist/plugins/schedules/record.d.ts +396 -0
- package/dist/plugins/schedules/service.d.ts +120 -0
- package/dist/plugins/schedules/time.d.ts +26 -0
- package/dist/plugins/schedules/tools.d.ts +6 -0
- package/dist/plugins/skills/discovery.d.ts +54 -0
- package/dist/plugins/skills/index.d.ts +31 -0
- package/dist/plugins/skills/index.js +1 -0
- package/dist/plugins/skills/tool.d.ts +11 -0
- package/dist/plugins/store/durableObject.d.ts +23 -0
- package/dist/plugins/store/durableObject.js +1 -0
- package/dist/plugins/store/durableObjectConnection.d.ts +27 -0
- package/dist/plugins/store/memory.d.ts +29 -0
- package/dist/plugins/store/sql.d.ts +59 -0
- package/dist/plugins/store/sqlite.d.ts +31 -0
- package/dist/plugins/store/sqlite.js +1 -0
- package/dist/plugins/subAgents/availableRoutes.d.ts +53 -0
- package/dist/plugins/subAgents/fork.d.ts +32 -0
- package/dist/plugins/subAgents/index.d.ts +67 -0
- package/dist/plugins/subAgents/index.js +1 -0
- package/dist/plugins/subAgents/tool.d.ts +38 -0
- package/dist/plugins/toolPolicy/index.d.ts +61 -0
- package/dist/plugins/toolPolicy/index.js +1 -0
- package/dist/plugins/tools/editFiles.d.ts +128 -0
- package/dist/plugins/tools/fsRead.d.ts +17 -0
- package/dist/plugins/tools/html.d.ts +23 -0
- package/dist/plugins/tools/index.d.ts +59 -0
- package/dist/plugins/tools/index.js +1 -0
- package/dist/plugins/tools/network.d.ts +23 -0
- package/dist/plugins/tools/ripgrep.d.ts +20 -0
- package/dist/plugins/tools/textEdit.d.ts +67 -0
- package/dist/plugins/tools/web.d.ts +32 -0
- package/dist/plugins/truncateToolOutput.d.ts +26 -0
- package/dist/plugins/truncateToolOutput.js +1 -0
- package/dist/plugins/usage/index.d.ts +24 -0
- package/dist/plugins/usage/index.js +1 -0
- package/dist/plugins/usage/tracker.d.ts +34 -0
- package/dist/plugins/verify/facts.d.ts +356 -0
- package/dist/plugins/verify/index.d.ts +75 -0
- package/dist/plugins/verify/index.js +1 -0
- package/dist/plugins/verify/service.d.ts +90 -0
- package/dist/plugins/workflows/assignment.d.ts +16 -0
- package/dist/plugins/workflows/bindings.d.ts +95 -0
- package/dist/plugins/workflows/cleanup.d.ts +38 -0
- package/dist/plugins/workflows/definition.d.ts +184 -0
- package/dist/plugins/workflows/fold.d.ts +373 -0
- package/dist/plugins/workflows/index.d.ts +28 -0
- package/dist/plugins/workflows/index.js +6 -0
- package/dist/plugins/workflows/observations.d.ts +81 -0
- package/dist/plugins/workflows/participants.d.ts +143 -0
- package/dist/plugins/workflows/policy.d.ts +112 -0
- package/dist/plugins/workflows/providers.d.ts +146 -0
- package/dist/plugins/workflows/record.d.ts +2863 -0
- package/dist/plugins/workflows/routing.d.ts +116 -0
- package/dist/plugins/workflows/schema.d.ts +26 -0
- package/dist/plugins/workflows/service.d.ts +477 -0
- package/dist/plugins/workflows/submit.d.ts +8 -0
- package/dist/plugins/workflows/view.d.ts +103 -0
- package/dist/plugins/workflows/work.d.ts +21 -0
- package/dist/plugins/workspaceContext.d.ts +38 -0
- package/dist/plugins/workspaceContext.js +1 -0
- package/dist/presets/agents.d.ts +7 -0
- package/dist/presets/base.d.ts +10 -0
- package/dist/presets/codex.d.ts +60 -0
- package/dist/presets/index.d.ts +4 -0
- package/dist/presets/prompts.d.ts +56 -0
- package/dist/sandbox/absent.d.ts +32 -0
- package/dist/sandbox/client.d.ts +39 -0
- package/dist/sandbox/files.d.ts +28 -0
- package/dist/sandbox/index.d.ts +49 -0
- package/dist/sandbox/index.js +4 -0
- package/dist/sandbox/mode.d.ts +57 -0
- package/dist/sandbox/policy.d.ts +86 -0
- package/dist/sandbox/protocol.d.ts +107 -0
- package/dist/sandbox/service.d.ts +143 -0
- package/dist/sandbox/worker.d.ts +12 -0
- package/dist/sandbox/worker.js +1 -0
- package/dist/services/admission.d.ts +174 -0
- package/dist/services/agents.d.ts +37 -0
- package/dist/services/birth.d.ts +220 -0
- package/dist/services/contributions.d.ts +73 -0
- package/dist/services/core.d.ts +34 -0
- package/dist/services/journal.d.ts +26 -0
- package/dist/services/launches.d.ts +104 -0
- package/dist/services/llm.d.ts +80 -0
- package/dist/services/owner.d.ts +367 -0
- package/dist/services/preset.d.ts +154 -0
- package/dist/services/presets.d.ts +139 -0
- package/dist/services/prompts.d.ts +67 -0
- package/dist/services/runEvents.d.ts +79 -0
- package/dist/services/thread.d.ts +267 -0
- package/dist/services/threadActivation.d.ts +100 -0
- package/dist/services/threadDirs.d.ts +38 -0
- package/dist/services/threadView.d.ts +92 -0
- package/dist/services/threads.d.ts +449 -0
- package/dist/services/tools.d.ts +41 -0
- package/dist/sys/environment.d.ts +47 -0
- package/dist/sys/git.d.ts +60 -0
- package/dist/sys/paths.d.ts +56 -0
- package/dist/sys/spawn.d.ts +176 -0
- package/dist/testing/clock.d.ts +17 -0
- package/dist/testing/fakeLlm.d.ts +74 -0
- package/dist/testing/fedLlm.d.ts +32 -0
- package/dist/testing/helpers.d.ts +344 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.js +1 -0
- package/dist/testing/processes.d.ts +13 -0
- package/dist/testing/sandbox.d.ts +71 -0
- package/dist/testing/settlement.d.ts +6 -0
- package/dist/testing/tmpDirs.d.ts +17 -0
- package/dist/util/async.d.ts +8 -0
- package/dist/util/diff.d.ts +25 -0
- package/dist/util/dispatch.d.ts +8 -0
- package/dist/util/errors.d.ts +28 -0
- package/dist/util/foldState.d.ts +17 -0
- package/dist/util/freeze.d.ts +2 -0
- package/dist/util/ids.d.ts +2 -0
- package/dist/util/json.d.ts +37 -0
- package/dist/util/log.d.ts +6 -0
- package/dist/util/text.d.ts +21 -0
- package/dist/util/version.d.ts +2 -0
- package/package.json +175 -3
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { JournalEvent, Seq, ThreadSummary } from '../models/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* One group's write: a fresh identity, the head it was numbered from, the writer's acquisition, and
|
|
4
|
+
* the rows. Immutable once made, so a write whose answer was lost can be sent again as it was.
|
|
5
|
+
*/
|
|
6
|
+
export type Attempt = {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly baseHead: Seq;
|
|
9
|
+
readonly writer: string;
|
|
10
|
+
readonly rows: readonly JournalEvent[];
|
|
11
|
+
};
|
|
12
|
+
/** What an append did: wrote the rows, or found the same attempt already written and wrote nothing. */
|
|
13
|
+
export type AppendOutcome = 'appended' | 'duplicate';
|
|
14
|
+
/** One thread as the store indexes it, from its rows alone: where it began and how far it reaches. */
|
|
15
|
+
export type ThreadIndexEntry = {
|
|
16
|
+
readonly threadId: string;
|
|
17
|
+
readonly spawnSeq: Seq;
|
|
18
|
+
readonly lastSeq: Seq;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The right to append: exclusive while held, with an acquisition id the store checks inside every
|
|
22
|
+
* append, so rows from a writer that lost the lease are refused rather than detected afterwards.
|
|
23
|
+
*/
|
|
24
|
+
export type WriterLease = {
|
|
25
|
+
/** What the lease is held on, for messages. */
|
|
26
|
+
readonly identity: string;
|
|
27
|
+
readonly acquisitionId: string;
|
|
28
|
+
release(): Promise<void>;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Durable backing for the journal: the rows, one thread at a time, an index of the threads, the
|
|
32
|
+
* catalog of summaries beside them, and the record of who may write. Every method is asynchronous,
|
|
33
|
+
* so a store across a network implements the same contract as SQLite; the conformance suite
|
|
34
|
+
* (`plugins/store/conformance.ts`) is what every store passes.
|
|
35
|
+
*
|
|
36
|
+
* `append` must be durable enough that a crash after it resolves still replays the rows, because
|
|
37
|
+
* nothing else records them. That is also why `read` refuses a row it cannot parse rather than
|
|
38
|
+
* skipping it: the conversation is derived from these rows, so a dropped one rewrites history.
|
|
39
|
+
*
|
|
40
|
+
* The catalog is written after the rows, by the journal, from folds that hold only durable rows; it
|
|
41
|
+
* can trail the rows by one group after a crash, and the thread index — kept in the append's own
|
|
42
|
+
* transaction — is how the journal finds the summaries to refresh when it opens.
|
|
43
|
+
*/
|
|
44
|
+
export declare abstract class JournalStore {
|
|
45
|
+
private opened;
|
|
46
|
+
get isOpen(): boolean;
|
|
47
|
+
/** Initializes resources and loads persisted state; idempotent. */
|
|
48
|
+
open(): Promise<void>;
|
|
49
|
+
/** Releases resources; idempotent. */
|
|
50
|
+
close(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Takes the writer lease, refused with {@link JournalBusyError} while another holds it. May be
|
|
53
|
+
* called before `open()`: a store whose exclusivity comes from the operating system takes it before
|
|
54
|
+
* reading anything.
|
|
55
|
+
*/
|
|
56
|
+
abstract acquireWriter(): Promise<WriterLease>;
|
|
57
|
+
/** The highest `seq` the store holds; 0 when it holds nothing. */
|
|
58
|
+
head(): Promise<Seq>;
|
|
59
|
+
/**
|
|
60
|
+
* Writes an attempt's rows as one unit — all of them survive a crash or none do — and indexes
|
|
61
|
+
* their thread, in one transaction, checked against three things in that transaction:
|
|
62
|
+
*
|
|
63
|
+
* - an attempt with this id already written is `duplicate` when its content — head, writer and
|
|
64
|
+
* rows — is the same, and {@link AttemptMismatchError} when it is not, before anything else is
|
|
65
|
+
* checked, so a resend after the head or the writer moved on is still recognized; an attempt's
|
|
66
|
+
* identity is kept as long as its rows;
|
|
67
|
+
* - the writer record must name `attempt.writer`, else {@link WriterLostError};
|
|
68
|
+
* - the head must still be `attempt.baseHead`, else {@link JournalConflictError}.
|
|
69
|
+
*
|
|
70
|
+
* The rows are one thread's, in ascending seq order above `baseHead` — consecutive as the journal
|
|
71
|
+
* writes them; a gap is allowed so a test can store a journal thinned on purpose — and a thread the
|
|
72
|
+
* index does not hold must begin with its spawn row. A thread has exactly one spawn row; a
|
|
73
|
+
* second is refused without writing any part of the attempt.
|
|
74
|
+
*
|
|
75
|
+
* A store that cannot tell whether a commit landed — a remote one whose answer was lost, say —
|
|
76
|
+
* should say so with a typed ambiguous failure: the journal can then send the same attempt again,
|
|
77
|
+
* and a `duplicate` answer proves the rows are durable, though not that this process still holds
|
|
78
|
+
* the writer lease. Neither shipped store can lose an answer, so the journal has no such resend
|
|
79
|
+
* yet; it is built with the store that needs it.
|
|
80
|
+
*/
|
|
81
|
+
append(attempt: Attempt): Promise<AppendOutcome>;
|
|
82
|
+
/** One thread's own rows, in `seq` order. A fork's source is read whole; the journal bounds the lineage. */
|
|
83
|
+
read(threadId: string): Promise<JournalEvent[]>;
|
|
84
|
+
/** The row at `seq`, whichever thread it belongs to. */
|
|
85
|
+
rowAt(seq: Seq): Promise<JournalEvent | undefined>;
|
|
86
|
+
/** Every thread the store holds, in spawn order: one entry per thread, whatever the journal's length. */
|
|
87
|
+
threads(): Promise<ThreadIndexEntry[]>;
|
|
88
|
+
/** Every summary the catalog holds, in spawn order. */
|
|
89
|
+
summaries(): Promise<ThreadSummary[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Writes summaries, each replacing its thread's unless the stored one already describes more of
|
|
92
|
+
* the thread (a higher `through_seq`): a late write never undoes a newer one. Checked against the
|
|
93
|
+
* writer record as an append is, else {@link WriterLostError}.
|
|
94
|
+
*/
|
|
95
|
+
putSummaries(summaries: readonly ThreadSummary[], writer: string): Promise<void>;
|
|
96
|
+
/** Replaces the whole catalog in one transaction: a rebuild's write, checked against the writer record. */
|
|
97
|
+
replaceCatalog(summaries: readonly ThreadSummary[], writer: string): Promise<void>;
|
|
98
|
+
protected abstract doOpen(): Promise<void>;
|
|
99
|
+
protected abstract doClose(): Promise<void>;
|
|
100
|
+
protected abstract doHead(): Promise<Seq>;
|
|
101
|
+
/** Implements {@link append}'s checks and write in one transaction; `digest` identifies the content. */
|
|
102
|
+
protected abstract doAppend(attempt: Attempt, digest: string): Promise<AppendOutcome>;
|
|
103
|
+
protected abstract doRead(threadId: string): Promise<JournalEvent[]>;
|
|
104
|
+
protected abstract doRowAt(seq: Seq): Promise<JournalEvent | undefined>;
|
|
105
|
+
protected abstract doThreads(): Promise<ThreadIndexEntry[]>;
|
|
106
|
+
protected abstract doSummaries(): Promise<ThreadSummary[]>;
|
|
107
|
+
protected abstract doPutSummaries(summaries: readonly ThreadSummary[], writer: string): Promise<void>;
|
|
108
|
+
protected abstract doReplaceCatalog(summaries: readonly ThreadSummary[], writer: string): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* The event as it stands.
|
|
111
|
+
*
|
|
112
|
+
* Nothing is normalized and nothing is dropped for size: a row that reads back differently from
|
|
113
|
+
* the event in memory makes a live process and a resumed one disagree about their own history,
|
|
114
|
+
* and the fields most able to disagree are the ones this engine does not model — what a provider
|
|
115
|
+
* needs back verbatim and the arguments the model sent a tool, neither of which has a schema to
|
|
116
|
+
* restore what a tidy-up removed. `llm/request` records the prompt as a size and digest precisely
|
|
117
|
+
* so that no row ever has to be trimmed.
|
|
118
|
+
*/
|
|
119
|
+
protected serialize(event: JournalEvent): string;
|
|
120
|
+
protected serializeSummary(summary: ThreadSummary): string;
|
|
121
|
+
private requireOpen;
|
|
122
|
+
}
|
|
123
|
+
/** The content identity of a whole attempt — head, writer and rows: what tells a resent attempt from a different one with the same id. */
|
|
124
|
+
export declare function digestOf(attempt: Pick<Attempt, 'baseHead' | 'writer' | 'rows'>): string;
|
|
125
|
+
export declare class JournalBusyError extends Error {
|
|
126
|
+
readonly location: string;
|
|
127
|
+
constructor(location: string);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* A write that waited its whole budget for another connection's write lock on the store, a shell or
|
|
131
|
+
* a backup say, and gave up. Nothing of it was written.
|
|
132
|
+
*/
|
|
133
|
+
export declare class StoreBusyError extends Error {
|
|
134
|
+
readonly location: string;
|
|
135
|
+
readonly waitedMs: number;
|
|
136
|
+
constructor(location: string, waitedMs: number);
|
|
137
|
+
}
|
|
138
|
+
/** An append numbered from a head the store has moved past: another writer, or a lost answer resent as new rows. */
|
|
139
|
+
export declare class JournalConflictError extends Error {
|
|
140
|
+
readonly expected: Seq;
|
|
141
|
+
readonly actual: Seq;
|
|
142
|
+
constructor(expected: Seq, actual: Seq);
|
|
143
|
+
}
|
|
144
|
+
/** An append by a writer the store's record no longer names: its lease was taken by another. */
|
|
145
|
+
export declare class WriterLostError extends Error {
|
|
146
|
+
readonly acquisitionId: string;
|
|
147
|
+
constructor(acquisitionId: string);
|
|
148
|
+
}
|
|
149
|
+
/** An attempt id already written with other rows: two different writes under one identity. */
|
|
150
|
+
export declare class AttemptMismatchError extends Error {
|
|
151
|
+
readonly attemptId: string;
|
|
152
|
+
constructor(attemptId: string);
|
|
153
|
+
}
|
|
154
|
+
/** A journal row that cannot be parsed by this build. */
|
|
155
|
+
export declare class CorruptJournalError extends Error {
|
|
156
|
+
readonly payload: string;
|
|
157
|
+
readonly cause: unknown;
|
|
158
|
+
constructor(payload: string, cause: unknown);
|
|
159
|
+
}
|
|
160
|
+
/** Parses one stored row; `shape` turns the parsed payload into the event's wire form when the store keeps it in parts. */
|
|
161
|
+
export declare function parseStoredEvent(payload: string, shape?: (stored: unknown) => unknown): JournalEvent;
|
|
162
|
+
export declare function parseStoredSummary(payload: string): ThreadSummary;
|
|
163
|
+
/**
|
|
164
|
+
* The journal format this build reads and writes. Bump it whenever the event alphabet or storage
|
|
165
|
+
* layout changes; a populated journal stamped with anything else is refused rather than partially read.
|
|
166
|
+
* A breaking change to persisted rows bumps it too, a plugin's extension row version bump included.
|
|
167
|
+
* Indexes enforcing existing invariants do not change the format.
|
|
168
|
+
*/
|
|
169
|
+
export declare const JOURNAL_VERSION = 38;
|
|
170
|
+
/** A journal written by a build whose format this one cannot read. */
|
|
171
|
+
export declare class IncompatibleJournalError extends Error {
|
|
172
|
+
readonly found: number;
|
|
173
|
+
readonly location: string;
|
|
174
|
+
constructor(found: number, location: string);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Judges a journal's version stamp on open. An empty journal is adopted whatever it says, and
|
|
178
|
+
* anything else holding rows is refused, because half a conversation is worse than none. A journal
|
|
179
|
+
* with no stamp at all reads as `0`.
|
|
180
|
+
*/
|
|
181
|
+
export declare function checkJournalVersion(stamped: number, hasRows: boolean, location: string): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* Claims `key`, a thread by its id or by its activation's scope, for the calling plugin within
|
|
4
|
+
* `kind`, for as long as the calling plugin's fiber lives: for a behaviour a thread runs at most
|
|
5
|
+
* once, such as an `AGENTS.md` briefing. `holder` is
|
|
6
|
+
* how a later refusal names this claim. Throws `refusal(holder)` with the holder of a live claim of
|
|
7
|
+
* the same kind on the same key, so the plugin that claimed later fails, and with it the
|
|
8
|
+
* activation, rather than running beside the first. Claims of different kinds never meet.
|
|
9
|
+
*
|
|
10
|
+
* Synchronous: the check and the claim are one step, and the claim is an effect of the caller's
|
|
11
|
+
* fiber, so a release, an unload or a failed setup frees the thread for the next activation.
|
|
12
|
+
*/
|
|
13
|
+
export declare function claimThread(ctx: Context, kind: string, key: unknown, holder: string, refusal: (holder: string) => string): void;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* Runs `drain` before any owner of `ctx` starts its cleanup, and before the journal's owner does:
|
|
4
|
+
* as an unload guard on every fiber from `ctx` up to the root, and on the fiber that provides the
|
|
5
|
+
* journal. Guards on one fiber run together before its disposers, so every service draining this
|
|
6
|
+
* way is signalled before any of them is awaited, and the journal is still writable for their final
|
|
7
|
+
* rows. `drain` must be idempotent, since several owners can unload, and must not await its own
|
|
8
|
+
* owner's teardown, which waits for the guard.
|
|
9
|
+
*/
|
|
10
|
+
export declare function drainBeforeUnload(ctx: Context, drain: () => Promise<void>): void;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { AppendOptions, PluginJournal, PluginProjection } from '../journal/index.js';
|
|
4
|
+
import type { ContentPartInput } from '../llm/index.js';
|
|
5
|
+
import { type ModelStep, type RowRef } from '../loop/index.js';
|
|
6
|
+
import { type AgentSelector } from './scope.js';
|
|
7
|
+
import type { ExtensionRecord, InputRole, JournalEvent, Seq, StepContribution } from '../models/index.js';
|
|
8
|
+
import type { ReadonlyState } from '../util/foldState.js';
|
|
9
|
+
import type { DeepReadonly } from '../util/json.js';
|
|
10
|
+
export declare class ExtensionVersionError extends Error {
|
|
11
|
+
readonly record: ExtensionRecord;
|
|
12
|
+
readonly supportedVersion: number;
|
|
13
|
+
constructor(record: ExtensionRecord, supportedVersion: number);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One plugin-owned event schema. A row of another version is refused with
|
|
17
|
+
* {@link ExtensionVersionError}: the journal is not migrated, and neither are a plugin's rows.
|
|
18
|
+
*
|
|
19
|
+
* `policyState` says a `lagent/tool/authorize` listener decides from these rows: one that lands
|
|
20
|
+
* while a call is authorized sends the decision round again. Rows of an event that does not say so
|
|
21
|
+
* never do, so diagnostics and notices cost an authorization nothing.
|
|
22
|
+
*/
|
|
23
|
+
export declare function defineExtensionEvent<Schema extends z.ZodType>(definition: {
|
|
24
|
+
plugin: string;
|
|
25
|
+
instanceId?: string;
|
|
26
|
+
kind: string;
|
|
27
|
+
version: number;
|
|
28
|
+
schema: Schema;
|
|
29
|
+
policyState?: boolean;
|
|
30
|
+
}): {
|
|
31
|
+
/** A validated record carrying `value`: what an `ext` row holds, and a contribution's `source`. */
|
|
32
|
+
record: (value: z.input<Schema>) => ExtensionRecord;
|
|
33
|
+
/** `value` validated as this event's payload, its defaults applied. */
|
|
34
|
+
parse: (value: z.input<Schema>) => z.output<Schema>;
|
|
35
|
+
/** A validated row for an atomic `journal.appendAll` batch; every row names its thread. */
|
|
36
|
+
entry: (value: z.input<Schema>, options: AppendOptions) => {
|
|
37
|
+
type: "ext";
|
|
38
|
+
data: {
|
|
39
|
+
plugin: string;
|
|
40
|
+
instance_id: string;
|
|
41
|
+
kind: string;
|
|
42
|
+
version: number;
|
|
43
|
+
data: z.core.util.JSONType;
|
|
44
|
+
};
|
|
45
|
+
options: AppendOptions;
|
|
46
|
+
};
|
|
47
|
+
/** Appends one row carrying `value`; resolves once it is durable. */
|
|
48
|
+
append(journal: PluginJournal, value: z.input<Schema>, options: AppendOptions): Promise<JournalEvent<"ext">>;
|
|
49
|
+
read(event: JournalEvent): z.output<Schema> | undefined;
|
|
50
|
+
/** A validated `lagent/llm/step` contribution whose `source` is this event carrying `value`. */
|
|
51
|
+
contribution(message: {
|
|
52
|
+
role?: InputRole;
|
|
53
|
+
content: string | readonly ContentPartInput[];
|
|
54
|
+
}, value: z.input<Schema>, options?: {
|
|
55
|
+
sourceSeqs?: readonly Seq[];
|
|
56
|
+
}): StepContribution;
|
|
57
|
+
/** Whether `record` — a contribution's or a rejection's `source` — is one of this event's. */
|
|
58
|
+
matchesSource(record: DeepReadonly<ExtensionRecord>): boolean;
|
|
59
|
+
/** A `lagent/turn/stop` rejection whose `source` is this event carrying `value`. */
|
|
60
|
+
rejection(reason: string, value: z.input<Schema>): {
|
|
61
|
+
decision: "reject";
|
|
62
|
+
reason: string;
|
|
63
|
+
source: ExtensionRecord;
|
|
64
|
+
};
|
|
65
|
+
/** The value a contributed `input/message` carries, when this event is its source. */
|
|
66
|
+
readContribution: (event: JournalEvent) => z.output<Schema> | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* The value `source` carries — a queued input's or a contribution's — when it is one of this
|
|
69
|
+
* event's; `undefined` for any other. Another version is refused, as for a row.
|
|
70
|
+
*/
|
|
71
|
+
readSource: (source: DeepReadonly<ExtensionRecord> | null) => z.output<Schema> | undefined;
|
|
72
|
+
/**
|
|
73
|
+
* What a thread was told through this event's contributions: every notice row, with the value
|
|
74
|
+
* it carried and whether it is still on the thread's surface. Read it with {@link latestNotice}
|
|
75
|
+
* and {@link latestVisible}.
|
|
76
|
+
*
|
|
77
|
+
* A thread was told something only while the notice is on its surface. A `surface/replaced`
|
|
78
|
+
* row that cites a notice row clears that row's visibility, for good; nothing else does. So a
|
|
79
|
+
* plugin that tells a thread a fact compares it with what the model can still see, and tells it
|
|
80
|
+
* again once a replacement took it away, with no scan of the surface at any step. Thread-scoped
|
|
81
|
+
* and inherited: a fork, and `stateAt`, see what was visible at their row of the lineage.
|
|
82
|
+
*/
|
|
83
|
+
told: PluginProjection<ToldNotices<z.output<Schema>>>;
|
|
84
|
+
/**
|
|
85
|
+
* Unrelated events are ignored. Failure makes this projection unavailable, not the journal.
|
|
86
|
+
*
|
|
87
|
+
* A fork inherits a thread-scoped state by default; `onFork: 'reset'` starts each fork from
|
|
88
|
+
* `init()` instead, for state that describes what the source did rather than its conversation.
|
|
89
|
+
* `apply` also gets the `ext` row that carried the value.
|
|
90
|
+
*/
|
|
91
|
+
projection<State>(fold: {
|
|
92
|
+
key: string;
|
|
93
|
+
init(): State;
|
|
94
|
+
apply(state: State, value: z.output<Schema>, event: JournalEvent<"ext">): State;
|
|
95
|
+
onFork?: "inherit" | "reset";
|
|
96
|
+
}): PluginProjection<State>;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* One notice a thread was told: the row that told it, the value its `source` carried, and whether
|
|
100
|
+
* the model can still see it.
|
|
101
|
+
*/
|
|
102
|
+
export type ToldNotice<Value> = {
|
|
103
|
+
readonly row: RowRef;
|
|
104
|
+
readonly value: Value;
|
|
105
|
+
/**
|
|
106
|
+
* Whether the notice is still on the thread's surface: cleared by the first `surface/replaced`
|
|
107
|
+
* row that cites it. What was recorded is one fact; whether the model can still see it, another.
|
|
108
|
+
*/
|
|
109
|
+
readonly visible: boolean;
|
|
110
|
+
};
|
|
111
|
+
/** Every notice of one kind a thread was told, oldest first: the state of an event's `told` fold. */
|
|
112
|
+
export type ToldNotices<Value> = {
|
|
113
|
+
readonly notices: readonly ToldNotice<Value>[];
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* The latest notice told, visible or not; `null` when none was ever told. For recorded text: a
|
|
117
|
+
* notice whose latest telling is no longer visible is told again from that row, as recorded.
|
|
118
|
+
*/
|
|
119
|
+
export declare function latestNotice<Value>(told: ToldNotices<Value>): ToldNotice<Value> | null;
|
|
120
|
+
/**
|
|
121
|
+
* What the latest notice the model can still see says; `null` when none is visible. For live facts:
|
|
122
|
+
* compare the fact as it stands with this, and tell it when they differ, rendered against this
|
|
123
|
+
* value, as a first telling when it is `null` and as a change from it otherwise.
|
|
124
|
+
*
|
|
125
|
+
* Not the latest notice's value: an earlier notice can outlive a later one. A restriction told
|
|
126
|
+
* early and lifted by a later notice that a replacement took away is still what the model sees, so
|
|
127
|
+
* the lift has to be told again.
|
|
128
|
+
*/
|
|
129
|
+
export declare function latestVisible<Value>(told: ToldNotices<Value>): Value | null;
|
|
130
|
+
/** What {@link tellOnStep} uses of an event `defineExtensionEvent` declared, `Input` and `Output` its payload's. */
|
|
131
|
+
export type NoticeEvent<Input, Output> = {
|
|
132
|
+
parse(value: Input): Output;
|
|
133
|
+
readonly told: PluginProjection<ToldNotices<Output>>;
|
|
134
|
+
contribution(message: {
|
|
135
|
+
content: string;
|
|
136
|
+
}, value: Input): StepContribution;
|
|
137
|
+
};
|
|
138
|
+
/** One fact a thread is told at its model steps; see {@link tellOnStep}. */
|
|
139
|
+
export type StepNotice<Input, Output> = {
|
|
140
|
+
/** The event each notice is recorded as, whose `told` fold says what the model can still see. */
|
|
141
|
+
readonly event: NoticeEvent<Input, Output>;
|
|
142
|
+
/** Whose threads are told; without it, every thread this plugin's listener reaches. */
|
|
143
|
+
readonly agents?: AgentSelector;
|
|
144
|
+
/**
|
|
145
|
+
* Where the notice is recorded among the step's contributions: lower first, equal ranks in
|
|
146
|
+
* listener order, 0 when omitted. See {@link ModelStep.contribute}.
|
|
147
|
+
*/
|
|
148
|
+
readonly rank?: number;
|
|
149
|
+
/** What is true for this step, or `undefined` to tell nothing at it. */
|
|
150
|
+
current(step: ModelStep): Input | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* The notice's text: `value` as a first telling when `told`, the latest notice the model can still
|
|
153
|
+
* see, is `null`, and as a change from it otherwise; `null` to tell nothing. `notices` is every
|
|
154
|
+
* notice of the event, for a plugin whose rule needs more than the latest visible one. What was
|
|
155
|
+
* told is read from the journal's fold, so it is the read-only view of `Output`.
|
|
156
|
+
*/
|
|
157
|
+
render(value: Output, told: ReadonlyState<Output> | null, at: {
|
|
158
|
+
readonly step: ModelStep;
|
|
159
|
+
readonly notices: ToldNotices<ReadonlyState<Output>>;
|
|
160
|
+
}): string | null;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Tells a thread a fact as a conversation message at its model steps: at each step already due,
|
|
164
|
+
* `current` says what is true, and when it differs from the latest notice the model can still see
|
|
165
|
+
* the step carries the rendered notice, recorded as the event. So a fact is told on the first step,
|
|
166
|
+
* again when it changes, and again after a replacement took the notice off the surface; several
|
|
167
|
+
* changes between two steps are one notice, and a change back is none. A plugin whose notice one
|
|
168
|
+
* plugin's failure must not silence keeps its own event, as every notice does. The event's schema
|
|
169
|
+
* must give the same value parsed twice, since the notice is recorded from `current` and compared
|
|
170
|
+
* after it is read back.
|
|
171
|
+
*
|
|
172
|
+
* ```ts
|
|
173
|
+
* tellOnStep(ctx, {
|
|
174
|
+
* event: routeNotice,
|
|
175
|
+
* current: (step) => step.route,
|
|
176
|
+
* render: (route, told) => (told === null ? `You run on ${route.model}.` : `You now run on ${route.model}.`),
|
|
177
|
+
* })
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
export declare function tellOnStep<Input, Output>(ctx: Context, notice: StepNotice<Input, Output>): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Context } from '@leuduan/cordis';
|
|
2
|
+
import type { AgentSelector } from './scope.js';
|
|
3
|
+
/**
|
|
4
|
+
* Grants `toolName` to the agents `agents` selects, for the life of the calling plugin's fiber, or
|
|
5
|
+
* until the returned disposer runs. The selector is stored as given: registries are live, so
|
|
6
|
+
* a grant to `'global'` or `'all'` is matched against each agent when it asks, agents registered
|
|
7
|
+
* later included.
|
|
8
|
+
*/
|
|
9
|
+
export declare function grantTool(ctx: Context, toolName: string, agents: AgentSelector): () => void | Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
import type { PluginJournal } from '../journal/index.js';
|
|
3
|
+
import type { WriteRows } from '../loop/index.js';
|
|
4
|
+
/** One set of durable modes, as {@link defineModes} takes it. */
|
|
5
|
+
export type ModesDefinition<Mode extends string> = {
|
|
6
|
+
/** Names the modes in the journal, so two sets never mix. */
|
|
7
|
+
readonly name: string;
|
|
8
|
+
/**
|
|
9
|
+
* Where a thread's mode is recorded and read: on the thread itself, or on its origin root
|
|
10
|
+
* (`Thread.originRoot`), so a delegated thread is in its conversation's mode and switching the
|
|
11
|
+
* conversation switches every thread it started.
|
|
12
|
+
*/
|
|
13
|
+
readonly authority: 'thread' | 'conversation';
|
|
14
|
+
/** The mode before one is recorded. */
|
|
15
|
+
readonly initial: NoInfer<Mode>;
|
|
16
|
+
/** Every mode the set has; what each one means belongs to the feature that reads it. */
|
|
17
|
+
readonly modes: readonly Mode[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* A set of durable modes: the state a feature reads to decide what a thread may do, and the host's
|
|
21
|
+
* way to set it. Each read and write takes a context that injects `journal` and `threads`.
|
|
22
|
+
*/
|
|
23
|
+
export type Modes<Mode extends string = string> = ModesDefinition<Mode> & {
|
|
24
|
+
/** The mode in force on `threadId`: its authority's latest recorded mode, or `initial`. */
|
|
25
|
+
of(ctx: Context, threadId: string): Mode;
|
|
26
|
+
/** Records `mode` on `threadId`'s authority, only when it changes it, decided inside the write. */
|
|
27
|
+
set(ctx: Context, threadId: string, mode: Mode): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* The rows that record `mode` in the write that creates or forks a thread (`Opening.rows`),
|
|
30
|
+
* so the thread never exists in another mode: always one row, `initial` included, so an opening
|
|
31
|
+
* leaves evidence of the choice (a fork would otherwise go on in the mode it inherits). The mode
|
|
32
|
+
* is validated here, before anything is written. Refused inside the write, which then records
|
|
33
|
+
* nothing, anywhere but an opening write, and for a thread with an `origin` under `conversation`
|
|
34
|
+
* authority, which is in its conversation's mode.
|
|
35
|
+
*/
|
|
36
|
+
opening(mode: Mode): WriteRows;
|
|
37
|
+
/**
|
|
38
|
+
* The thread a mode is recorded on for `threadId`: itself, or for `conversation`, its
|
|
39
|
+
* `originRoot`. Throws {@link MissingAuthorityError} when that root cannot be found, so no thread
|
|
40
|
+
* part-way up is taken for it; a thread the catalog does not hold is its own.
|
|
41
|
+
*/
|
|
42
|
+
authorityOf(ctx: Context, threadId: string): string;
|
|
43
|
+
/** The mode recorded on `threadId` itself, or `null`: what a catalog contribution computes. */
|
|
44
|
+
recorded(journal: PluginJournal, threadId: string): Mode | null;
|
|
45
|
+
};
|
|
46
|
+
/** A conversation mode asked for a thread whose caller chain does not reach its origin root. */
|
|
47
|
+
export declare class MissingAuthorityError extends Error {
|
|
48
|
+
constructor(threadId: string, modes: string);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Defines a set of durable modes, once per `name` in a process. A mode is an `ext` row on the
|
|
52
|
+
* authority thread, declared policy state, so a switch while a call is authorized decides it again.
|
|
53
|
+
* The set owns that state only: what a mode means, and what the model is told about it, belong to
|
|
54
|
+
* the feature that reads it (see `toolPolicy`).
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const permissions = defineModes<'ask' | 'auto'>({
|
|
58
|
+
* name: 'app:permission',
|
|
59
|
+
* authority: 'conversation',
|
|
60
|
+
* initial: 'ask',
|
|
61
|
+
* modes: ['ask', 'auto'],
|
|
62
|
+
* })
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function defineModes<Mode extends string>(definition: ModesDefinition<Mode>): Modes<Mode>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Clock } from './timers.js';
|
|
2
|
+
/**
|
|
3
|
+
* Consecutive failures and the retry timer of work whose write failed, by key: what ask, schedules
|
|
4
|
+
* and delegations each kept beside their deadlines. Owns the counts and one timer queue of retries;
|
|
5
|
+
* the feature keeps its liveness checks, its deadlines, its reporting and what a retry does. There
|
|
6
|
+
* is no attempt identity: a retry is the feature's own check, which decides again from current state.
|
|
7
|
+
*/
|
|
8
|
+
export type RetryTracker = {
|
|
9
|
+
/**
|
|
10
|
+
* Records one more failure of `key` and arms `retry` after the backoff its count earns, replacing a
|
|
11
|
+
* retry already pending for it. The retry firing keeps the count: only `succeeded` or `clear`
|
|
12
|
+
* resets it. Inert once disposed.
|
|
13
|
+
*/
|
|
14
|
+
failed(key: string, retry: () => void): void;
|
|
15
|
+
/** `key`'s work went through: its count and pending retry are forgotten. */
|
|
16
|
+
succeeded(key: string): void;
|
|
17
|
+
/** `key`'s work is no longer wanted: its count and pending retry are forgotten. */
|
|
18
|
+
clear(key: string): void;
|
|
19
|
+
/** Whether `key` has failed since it last succeeded or was cleared, its retry pending or in flight. */
|
|
20
|
+
pending(key: string): boolean;
|
|
21
|
+
/** Cancels every retry and forgets every count; later calls do nothing. Whoever creates a tracker disposes it. */
|
|
22
|
+
dispose(): void;
|
|
23
|
+
};
|
|
24
|
+
/** A {@link RetryTracker} whose retries are timed on `clock`; a retry that throws is handed to `report`. */
|
|
25
|
+
export declare function retryTracker(clock: Clock, report: (error: unknown) => void): RetryTracker;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Context } from '@leuduan/cordis';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* The agents a plugin's `agents` option selects. Required wherever it appears: which agents a
|
|
5
|
+
* composition has is the host's to say, so none of the shipped plugins defaults it. `'global'` is
|
|
6
|
+
* every globally registered agent, those registered later included; `'all'` is every thread's agent,
|
|
7
|
+
* scoped ones included; a list names agents, global or scoped.
|
|
8
|
+
*/
|
|
9
|
+
export declare const AgentSelectorSchema: z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodLiteral<"global">, z.ZodLiteral<"all">]>;
|
|
10
|
+
export type AgentSelector = readonly string[] | 'global' | 'all';
|
|
11
|
+
/**
|
|
12
|
+
* Whether `selector` selects `agentName`. One meaning wherever a selector appears, whether the plugin
|
|
13
|
+
* equips (a grant, a prompt section, a notice) or restricts (a mode, a stop check). `'global'` never
|
|
14
|
+
* selects a scoped agent (`isScopedAgentName`), so a role child gets only what names it or says
|
|
15
|
+
* `'all'`; a gate that must cover role children says `'all'`.
|
|
16
|
+
*
|
|
17
|
+
* Registries are live, so a selector is a predicate evaluated when the plugin acts — granting,
|
|
18
|
+
* rendering a prompt section, authorizing a call — rather than a list resolved once at mount.
|
|
19
|
+
*/
|
|
20
|
+
export declare const selects: (selector: AgentSelector, agentName: string) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Whether `name` is an agent name for a scoped registration: one containing a dot, such as
|
|
23
|
+
* `codex.explore`. Global agent names never contain one, so the two kinds cannot collide, and the
|
|
24
|
+
* agents registry refuses a registration of the wrong kind.
|
|
25
|
+
*/
|
|
26
|
+
export declare const isScopedAgentName: (name: string) => boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Refuses a plugin mounted in a thread's scope when `name`, the thing mounted, serves every thread
|
|
29
|
+
* from the application root. The predicate is `scopeOf(ctx) === undefined`: an untagged application
|
|
30
|
+
* context passes, so this is not a root-identity check.
|
|
31
|
+
*/
|
|
32
|
+
export declare function requireUnscoped(ctx: Context, name: string): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
/**
|
|
3
|
+
* The root service `name`, or a refusal naming `user`, the plugin or tool that depends on it, when
|
|
4
|
+
* it is not mounted. Checked where a plugin mounts, so a composition without the service fails
|
|
5
|
+
* there rather than leaving the plugin silently inactive, and looked up again at each call.
|
|
6
|
+
*/
|
|
7
|
+
export declare function requireService<K extends string & keyof Context>(ctx: Context, name: K, user: string): NonNullable<Context[K]>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Context } from '@leuduan/cordis';
|
|
2
|
+
import type { SurfaceStrategy } from '../loop/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Makes `strategy` the one that prepares `threadId`'s surface, for as long as the calling plugin's
|
|
5
|
+
* fiber lives. A thread runs one strategy: a second, from another mount or installation, throws, so
|
|
6
|
+
* the plugin that came later fails, and with it the activation, rather than running beside the first.
|
|
7
|
+
*/
|
|
8
|
+
export declare function provideStrategy(ctx: Context, threadId: string, strategy: SurfaceStrategy): void;
|
|
9
|
+
/** The strategy that prepares `threadId`'s surface, if any. */
|
|
10
|
+
export declare function strategyOf(ctx: Context, threadId: string): SurfaceStrategy | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Wall-clock time and timers, for a plugin that acts at a time of day: what it reads `now` from
|
|
4
|
+
* and arms its timer on, passed in by the application so a test moves both itself.
|
|
5
|
+
*/
|
|
6
|
+
export type Clock = {
|
|
7
|
+
/** Wall-clock milliseconds since the epoch, as `Date.now()`. */
|
|
8
|
+
now(): number;
|
|
9
|
+
/** Calls `fire` once, `ms` of elapsed time from now; returns the cancel. */
|
|
10
|
+
setTimer(ms: number, fire: () => void): () => void;
|
|
11
|
+
};
|
|
12
|
+
/** A configuration field that takes a {@link Clock}: `systemClock` in an application, a manual clock in a test. */
|
|
13
|
+
export declare const ClockSchema: z.ZodCustom<Clock, Clock>;
|
|
14
|
+
/**
|
|
15
|
+
* The process's clock: `Date.now()` and `setTimeout`, its timers `unref`'d so a pending wake never
|
|
16
|
+
* keeps a process alive.
|
|
17
|
+
*/
|
|
18
|
+
export declare const systemClock: Clock;
|
|
19
|
+
/** The longest one wait lasts: every wake reads the wall clock again, so a jump is noticed within it. */
|
|
20
|
+
export declare const MAX_WAIT_MS = 60000;
|
|
21
|
+
/**
|
|
22
|
+
* How long to put off work whose write failed, after `failures` failures in a row: a second, doubling
|
|
23
|
+
* up to ten minutes, so a store that fails for a while is not hammered and one that recovers is
|
|
24
|
+
* tried again soon.
|
|
25
|
+
*/
|
|
26
|
+
export declare function retryDelayMs(failures: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Keyed deadlines on one process timer: `set` (re)arms a key for a wall-clock time, `delete`
|
|
29
|
+
* forgets it, `dispose` cancels the timer and drops every entry. Entries fire in deadline order,
|
|
30
|
+
* each once, when a wake finds the wall clock at or past it; its key is removed before it fires.
|
|
31
|
+
*/
|
|
32
|
+
export type TimerQueue = {
|
|
33
|
+
set(key: string, at: number, fire: () => void): void;
|
|
34
|
+
delete(key: string): void;
|
|
35
|
+
dispose(): void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* A {@link TimerQueue} on `clock`: one timer for the earliest deadline, each wait clamped to
|
|
39
|
+
* {@link MAX_WAIT_MS}, and `now()` read again at every wake, so a wall clock set back is absorbed
|
|
40
|
+
* and one set forward is noticed within a minute. Whoever creates a queue owns it, and disposes it.
|
|
41
|
+
* A `fire` that throws is handed to `report`; the others still fire.
|
|
42
|
+
*/
|
|
43
|
+
export declare function timerQueue(clock: Clock, report: (error: unknown) => void): TimerQueue;
|