@xandreed/core 0.3.0 → 0.8.0-next.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/README.md +1 -1
- package/dist/conformance.entity.d.ts +15 -0
- package/dist/conformance.entity.js +7 -0
- package/dist/decision-record.entity.d.ts +31 -0
- package/dist/decision-record.entity.functions.d.ts +6 -0
- package/dist/decision-record.entity.functions.js +3 -0
- package/dist/decision-record.entity.js +24 -0
- package/dist/domain/agent-failure.entity.d.ts +6 -6
- package/dist/domain/agent-failure.entity.js +12 -1
- package/dist/domain/failure.entity.d.ts +2 -2
- package/dist/domain/loop-event.entity.d.ts +2 -0
- package/dist/domain/message.entity.d.ts +143 -156
- package/dist/domain/message.entity.js +6 -6
- package/dist/domain/model-call-policy.entity.d.ts +3 -3
- package/dist/domain/model-call-policy.entity.js +1 -1
- package/dist/domain/model-catalog.entity.d.ts +4 -4
- package/dist/domain/model-catalog.entity.js +1 -1
- package/dist/domain/model-selection.entity.d.ts +6 -13
- package/dist/domain/prompt-provenance.entity.d.ts +6 -6
- package/dist/domain/prompt-provenance.entity.js +4 -4
- package/dist/domain/token-usage.entity.d.ts +4 -4
- package/dist/harness/capability.entity.d.ts +88 -41
- package/dist/harness/capability.entity.functions.d.ts +30 -1
- package/dist/harness/capability.entity.functions.js +55 -2
- package/dist/harness/capability.entity.js +33 -12
- package/dist/harness/config.entity.d.ts +28 -28
- package/dist/harness/config.entity.js +4 -4
- package/dist/harness/plugin-stack.adapter.d.ts +24 -0
- package/dist/harness/plugin-stack.adapter.js +8 -0
- package/dist/harness/plugin-stack.adapter.test.d.ts +1 -0
- package/dist/harness/plugin.adapter.d.ts +15 -4
- package/dist/harness/plugin.adapter.js +18 -11
- package/dist/harness/plugin.adapter.test.d.ts +1 -0
- package/dist/harness/plugin.entity.d.ts +26 -10
- package/dist/harness/plugin.entity.js +1 -1
- package/dist/harness/session.entity.d.ts +20 -20
- package/dist/harness/session.entity.js +1 -1
- package/dist/harness/skill-files.d.ts +17 -0
- package/dist/harness/skill-files.js +25 -0
- package/dist/index.d.ts +48 -4
- package/dist/index.js +46 -4
- package/dist/loop/cacheKey.d.ts +3 -3
- package/dist/loop/cacheKey.js +4 -2
- package/dist/loop/mapping.d.ts +4 -5
- package/dist/loop/mapping.js +8 -16
- package/dist/loop/modelPolicy.d.ts +4 -4
- package/dist/loop/modelPolicy.js +2 -2
- package/dist/loop/promptProvenance.d.ts +2 -2
- package/dist/loop/promptProvenance.js +2 -2
- package/dist/loop/stepContext.d.ts +2 -2
- package/dist/loop/stepContext.js +2 -2
- package/dist/loop/streamFold.js +3 -3
- package/dist/loop/toolSchema.d.ts +17 -0
- package/dist/loop/toolSchema.js +25 -0
- package/dist/loop/toolSchema.test.d.ts +1 -0
- package/dist/mcp/bridge.d.ts +15 -15
- package/dist/mcp/bridge.js +14 -14
- package/dist/memory/memory-log.entity.d.ts +320 -0
- package/dist/memory/memory-log.entity.functions.d.ts +89 -0
- package/dist/memory/memory-log.entity.functions.js +180 -0
- package/dist/memory/memory-log.entity.js +75 -0
- package/dist/memory/memory-log.entity.test.d.ts +1 -0
- package/dist/memory/memory-session.d.ts +51 -0
- package/dist/memory/memory-session.js +97 -0
- package/dist/memory/memory-session.test.d.ts +1 -0
- package/dist/memory/memory.conformance.d.ts +32 -0
- package/dist/memory/memory.conformance.js +102 -0
- package/dist/ports/auth-store.port.d.ts +16 -18
- package/dist/ports/auth-store.port.js +13 -9
- package/dist/ports/capability.port.d.ts +131 -7
- package/dist/ports/capability.port.js +2 -2
- package/dist/ports/conversation-store.port.d.ts +54 -177
- package/dist/ports/conversation-store.port.js +9 -9
- package/dist/ports/file-system.port.d.ts +5 -7
- package/dist/ports/file-system.port.js +1 -1
- package/dist/ports/harness.port.d.ts +19 -13
- package/dist/ports/harness.port.js +10 -10
- package/dist/ports/mcp-client.port.d.ts +15 -47
- package/dist/ports/mcp-client.port.js +3 -3
- package/dist/ports/memory.port.d.ts +116 -0
- package/dist/ports/memory.port.js +7 -0
- package/dist/ports/model-catalog.port.d.ts +1 -1
- package/dist/ports/model-catalog.port.js +1 -1
- package/dist/ports/permission.port.d.ts +10 -0
- package/dist/ports/permission.port.js +4 -0
- package/dist/ports/run-context.port.d.ts +28 -0
- package/dist/ports/run-context.port.js +4 -0
- package/dist/ports/session-log.port.d.ts +25 -0
- package/dist/ports/session-log.port.js +4 -0
- package/dist/ports/sessions.port.d.ts +141 -0
- package/dist/ports/sessions.port.js +4 -0
- package/dist/ports/settings-store.port.d.ts +18 -56
- package/dist/ports/settings-store.port.js +3 -3
- package/dist/ports/shell.port.d.ts +9 -21
- package/dist/ports/shell.port.js +1 -1
- package/dist/ports/step-loop.port.d.ts +85 -0
- package/dist/ports/step-loop.port.js +4 -0
- package/dist/ports/tasks.port.d.ts +59 -0
- package/dist/ports/tasks.port.js +10 -0
- package/dist/ports/tool-registry.port.d.ts +53 -0
- package/dist/ports/tool-registry.port.js +4 -0
- package/dist/ports/turn-admission.port.d.ts +23 -0
- package/dist/ports/turn-admission.port.js +4 -0
- package/dist/ports/turn-events.port.d.ts +55 -0
- package/dist/ports/turn-events.port.js +7 -0
- package/dist/ports/turn-scope.port.d.ts +101 -0
- package/dist/ports/turn-scope.port.js +10 -0
- package/dist/ports/turn.port.d.ts +113 -0
- package/dist/ports/turn.port.js +0 -0
- package/dist/ports/utility-llm.port.d.ts +12 -31
- package/dist/ports/utility-llm.port.js +1 -1
- package/dist/session/chassis.js +7 -7
- package/dist/session/session-event.entity.d.ts +55 -0
- package/dist/session/session-event.entity.functions.d.ts +31 -0
- package/dist/session/session-event.entity.functions.js +42 -0
- package/dist/session/session-event.entity.js +37 -0
- package/dist/session/session-event.entity.test.d.ts +1 -0
- package/dist/session/session-log.conformance.d.ts +13 -0
- package/dist/session/session-log.conformance.js +167 -0
- package/dist/session/session-log.entity.d.ts +164 -0
- package/dist/session/session-log.entity.js +82 -0
- package/dist/session/session-log.memory.adapter.d.ts +7 -0
- package/dist/session/session-log.memory.adapter.js +82 -0
- package/dist/session/session-log.memory.adapter.test.d.ts +1 -0
- package/dist/session/sessions.entity.d.ts +201 -0
- package/dist/session/sessions.entity.js +98 -0
- package/dist/session/tasks.entity.d.ts +39 -0
- package/dist/session/tasks.entity.js +26 -0
- package/dist/session/turn-admission.open.adapter.d.ts +4 -0
- package/dist/session/turn-admission.open.adapter.js +3 -0
- package/dist/spec/SpecDoc.d.ts +30 -117
- package/dist/spec/SpecDoc.js +10 -10
- package/dist/spec/codec.js +1 -1
- package/dist/turn/model-request.entity.d.ts +99 -0
- package/dist/turn/model-request.entity.functions.d.ts +108 -0
- package/dist/turn/model-request.entity.functions.js +167 -0
- package/dist/turn/model-request.entity.js +41 -0
- package/dist/turn/model-request.entity.test.d.ts +1 -0
- package/dist/turn/prompt-sections.d.ts +10 -0
- package/dist/turn/prompt-sections.js +3 -0
- package/dist/turn/step-loop.conformance.d.ts +16 -0
- package/dist/turn/step-loop.conformance.js +164 -0
- package/dist/turn/testing.d.ts +30 -0
- package/dist/turn/turn-bus.d.ts +23 -0
- package/dist/turn/turn-bus.js +54 -0
- package/dist/turn/turn-bus.test.d.ts +1 -0
- package/dist/turn/turn-event.entity.d.ts +263 -0
- package/dist/turn/turn-event.entity.functions.d.ts +35 -0
- package/dist/turn/turn-event.entity.functions.js +21 -0
- package/dist/turn/turn-event.entity.js +101 -0
- package/dist/turn/turn-lifecycle.d.ts +32 -0
- package/dist/turn/turn-lifecycle.js +48 -0
- package/dist/turn/turn-run.d.ts +26 -0
- package/dist/turn/turn-run.js +105 -0
- package/dist/turn/turn.adapter.d.ts +21 -0
- package/dist/turn/turn.adapter.js +126 -0
- package/dist/turn/turn.adapter.test.d.ts +1 -0
- package/dist/turn/turn.conformance.d.ts +20 -0
- package/dist/turn/turn.conformance.js +74 -0
- package/dist/turn/user-message.entity.d.ts +14 -0
- package/dist/turn/user-message.entity.js +10 -0
- package/dist/util/json.d.ts +2 -2
- package/dist/util/json.js +10 -10
- package/package.json +2 -3
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect, Option, Scope } from "effect";
|
|
3
|
+
import type { AgentMessage, ConversationId } from "../domain/message.entity.js";
|
|
4
|
+
import type { TokenUsage } from "../domain/token-usage.entity.js";
|
|
5
|
+
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
6
|
+
import type { LogQuery } from "../memory/memory-log.entity.functions.js";
|
|
7
|
+
import type { ArtifactRef, BuiltContext, EntryId, LogBody, LogEntry, Subject } from "../memory/memory-log.entity.js";
|
|
8
|
+
import type { UserMessage } from "../turn/user-message.entity.js";
|
|
9
|
+
import type { MemoryRenderRecipe } from "../turn/model-request.entity.js";
|
|
10
|
+
/** A conversation's memory log for one turn: the entries stored before it, and one atomic append. */
|
|
11
|
+
export interface LogHandle {
|
|
12
|
+
readonly read: Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
13
|
+
readonly append: (entries: ReadonlyArray<LogEntry>) => Effect.Effect<void, HarnessError>;
|
|
14
|
+
}
|
|
15
|
+
/** One tool result as the model sees it, supplied by whoever owns the tools. */
|
|
16
|
+
export interface ToolView {
|
|
17
|
+
readonly text: string;
|
|
18
|
+
readonly version: string;
|
|
19
|
+
readonly subjects: ReadonlyArray<Subject>;
|
|
20
|
+
readonly artifacts: ReadonlyArray<ArtifactRef>;
|
|
21
|
+
readonly pinned: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** What the digester returns: the item keys to keep, or a summary. */
|
|
24
|
+
export interface DigestOutcome {
|
|
25
|
+
readonly keep: ReadonlyArray<string>;
|
|
26
|
+
readonly summary: Option.Option<string>;
|
|
27
|
+
}
|
|
28
|
+
/** One result prepared for digestion by the tool that produced it. */
|
|
29
|
+
export interface DigestTask {
|
|
30
|
+
readonly tool: string;
|
|
31
|
+
readonly version: string;
|
|
32
|
+
readonly mode: "select" | "summarize";
|
|
33
|
+
/** The tool's own digest prompt. */
|
|
34
|
+
readonly instructions: string;
|
|
35
|
+
/** The user message the digest must serve. */
|
|
36
|
+
readonly userMessage: UserMessage;
|
|
37
|
+
/** Select mode: the keyed items the digester chooses from. */
|
|
38
|
+
readonly items: ReadonlyArray<{
|
|
39
|
+
readonly key: string;
|
|
40
|
+
readonly text: string;
|
|
41
|
+
}>;
|
|
42
|
+
/** The full rendered result (summarize mode's input). */
|
|
43
|
+
readonly source: string;
|
|
44
|
+
/** The text the model will see for this outcome; None keeps the original view. */
|
|
45
|
+
readonly apply: (outcome: DigestOutcome) => Option.Option<string>;
|
|
46
|
+
}
|
|
47
|
+
/** Tool views by name — the memory strategy applies them without knowing any tool. */
|
|
48
|
+
export interface ToolViews {
|
|
49
|
+
readonly view: (tool: string, encoded: unknown, params: unknown, isError: boolean) => Effect.Effect<ToolView>;
|
|
50
|
+
/** The older-turn form; None keeps the write-time view. */
|
|
51
|
+
readonly compact: (tool: string, encoded: unknown, params: unknown) => Effect.Effect<Option.Option<string>>;
|
|
52
|
+
/** The tool's digest of this result, when it declares one. */
|
|
53
|
+
readonly digest: (tool: string, encoded: unknown, params: unknown, userMessage: UserMessage) => Effect.Effect<Option.Option<DigestTask>>;
|
|
54
|
+
}
|
|
55
|
+
declare const ResultDigester_base: Context.ServiceClass<ResultDigester, "efferent/ResultDigester", {
|
|
56
|
+
readonly id: string;
|
|
57
|
+
readonly version: string;
|
|
58
|
+
readonly digest: (task: DigestTask) => Effect.Effect<DigestOutcome, HarnessError>;
|
|
59
|
+
}>;
|
|
60
|
+
/** Runs a tool's digest prompt (see `DigestDefinition`). Read, when present, from where the session is opened. */
|
|
61
|
+
export declare class ResultDigester extends ResultDigester_base {
|
|
62
|
+
}
|
|
63
|
+
/** Read-only memory for tools, sections, matchers and reactions. */
|
|
64
|
+
export interface MemoryReader {
|
|
65
|
+
readonly turn: Effect.Effect<number>;
|
|
66
|
+
readonly entries: Effect.Effect<ReadonlyArray<LogEntry>>;
|
|
67
|
+
readonly query: (query: LogQuery) => Effect.Effect<ReadonlyArray<LogEntry>>;
|
|
68
|
+
readonly subjects: (kinds: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<Subject>>;
|
|
69
|
+
readonly resolve: (id: EntryId) => Effect.Effect<Option.Option<LogEntry>>;
|
|
70
|
+
readonly transcript: (fidelity: "raw" | "model" | "reference") => Effect.Effect<ReadonlyArray<AgentMessage>>;
|
|
71
|
+
}
|
|
72
|
+
export interface MaintainSignal {
|
|
73
|
+
readonly phase: "turn-start" | "step";
|
|
74
|
+
readonly lastUsage: Option.Option<TokenUsage>;
|
|
75
|
+
/** Tokens available to the messages (system and tool schemas already deducted). */
|
|
76
|
+
readonly budgetTokens: number;
|
|
77
|
+
readonly views: ToolViews;
|
|
78
|
+
}
|
|
79
|
+
export interface MemorySession extends MemoryReader {
|
|
80
|
+
readonly strategy: {
|
|
81
|
+
readonly id: string;
|
|
82
|
+
readonly version: string;
|
|
83
|
+
};
|
|
84
|
+
/** The pure render recipe of this session, saved with every outgoing request for version-independent replay. */
|
|
85
|
+
readonly renderRecipe: (stepContext: "tail" | "none") => Effect.Effect<MemoryRenderRecipe>;
|
|
86
|
+
readonly record: (bodies: ReadonlyArray<LogBody>, step: number) => Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
87
|
+
/** The loop's appended messages → Message and ToolResult entries (views, and digests the strategy asks for, at write time). */
|
|
88
|
+
readonly recordTail: (tail: ReadonlyArray<AgentMessage>, views: ToolViews, step: number) => Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
89
|
+
/** The only place compaction is decided; the decision is recorded before it applies. */
|
|
90
|
+
readonly maintain: (signal: MaintainSignal) => Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
91
|
+
/** A pure fold of the log: what the next request sends. */
|
|
92
|
+
readonly build: (request: {
|
|
93
|
+
readonly stepContext: "tail" | "none";
|
|
94
|
+
}) => Effect.Effect<BuiltContext, HarnessError>;
|
|
95
|
+
}
|
|
96
|
+
declare const ConversationMemory_base: Context.ServiceClass<ConversationMemory, "efferent/ConversationMemory", {
|
|
97
|
+
readonly strategy: {
|
|
98
|
+
readonly id: string;
|
|
99
|
+
readonly version: string;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Open the conversation's session for one run over its log (the turn's
|
|
103
|
+
* memory events). A strategy reads what it needs per turn (a
|
|
104
|
+
* ResultDigester, a summarizer's UtilityLlm) with `Effect.serviceOption`
|
|
105
|
+
* from the environment it is opened in.
|
|
106
|
+
*/
|
|
107
|
+
readonly open: (scope: {
|
|
108
|
+
readonly conversation: ConversationId;
|
|
109
|
+
readonly runId: string;
|
|
110
|
+
readonly log: LogHandle;
|
|
111
|
+
}) => Effect.Effect<MemorySession, HarnessError, Scope.Scope>;
|
|
112
|
+
}>;
|
|
113
|
+
/** STRATEGY: how memory is kept, compacted and rebuilt. Swap this plugin to swap memory. */
|
|
114
|
+
export declare class ConversationMemory extends ConversationMemory_base {
|
|
115
|
+
}
|
|
116
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect } from "effect";
|
|
3
3
|
import type { ModelCatalogEntry } from "../domain/model-catalog.entity.js";
|
|
4
|
-
declare const ModelCatalog_base: Context.
|
|
4
|
+
declare const ModelCatalog_base: Context.ServiceClass<ModelCatalog, "@xandreed/core/ModelCatalog", {
|
|
5
5
|
readonly list: Effect.Effect<ReadonlyArray<ModelCatalogEntry>>;
|
|
6
6
|
}>;
|
|
7
7
|
/** Provider-neutral discovery of models usable by configured adapters. */
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect } from "effect";
|
|
3
|
+
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
4
|
+
declare const PermissionGrants_base: Context.ServiceClass<PermissionGrants, "efferent/PermissionGrants", {
|
|
5
|
+
readonly grants: Effect.Effect<ReadonlySet<string>, HarnessError>;
|
|
6
|
+
}>;
|
|
7
|
+
/** The permissions a run holds; skills and tools needing others are never activated. */
|
|
8
|
+
export declare class PermissionGrants extends PermissionGrants_base {
|
|
9
|
+
}
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect } from "effect";
|
|
3
|
+
import type { ConversationId } from "../domain/message.entity.js";
|
|
4
|
+
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
5
|
+
import type { SessionAddress } from "../session/sessions.entity.js";
|
|
6
|
+
import type { UserMessage } from "../turn/user-message.entity.js";
|
|
7
|
+
import type { MemoryReader } from "./memory.port.js";
|
|
8
|
+
import type { TurnEventsService, TurnTasksService } from "./turn-events.port.js";
|
|
9
|
+
declare const RunContext_base: Context.ServiceClass<RunContext, "efferent/RunContext", {
|
|
10
|
+
readonly conversation: ConversationId;
|
|
11
|
+
/** The session the turn runs in, as its owner names it. */
|
|
12
|
+
readonly session: SessionAddress;
|
|
13
|
+
readonly runId: string;
|
|
14
|
+
readonly userMessage: UserMessage;
|
|
15
|
+
readonly memory: MemoryReader;
|
|
16
|
+
readonly events: TurnEventsService;
|
|
17
|
+
readonly tasks: TurnTasksService;
|
|
18
|
+
/** Host-initiated skill activation (e.g. a handler that needs another skill next step). */
|
|
19
|
+
readonly activate: (skills: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<string>, HarnessError>;
|
|
20
|
+
/** Wait until every journal write queued so far is stored (before an externally visible action). */
|
|
21
|
+
readonly flush: Effect.Effect<void, HarnessError>;
|
|
22
|
+
/** Run a host store write in journal order (after everything queued before it). */
|
|
23
|
+
readonly write: <A, E>(op: Effect.Effect<A, E>) => Effect.Effect<A, E | HarnessError>;
|
|
24
|
+
}>;
|
|
25
|
+
/** The current run, as tools, sections and run layers see it. Provided by the turn. */
|
|
26
|
+
export declare class RunContext extends RunContext_base {
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect } from "effect";
|
|
3
|
+
import type { ConversationId } from "../domain/message.entity.js";
|
|
4
|
+
import type { LeaseExpired, RevisionConflict, SessionCommit, SessionCommitted, SessionExists, SessionHead, SessionHeader, SessionListQuery, SessionLogError, SessionLogEvent, SessionMissing, SessionReadQuery } from "../session/session-log.entity.js";
|
|
5
|
+
declare const SessionLog_base: Context.ServiceClass<SessionLog, "efferent/SessionLog", {
|
|
6
|
+
/** Create an empty session (seq 0, revision 0). A child's parent must exist. */
|
|
7
|
+
readonly create: (header: SessionHeader) => Effect.Effect<SessionHead, SessionExists | SessionMissing | SessionLogError>;
|
|
8
|
+
readonly head: (id: ConversationId) => Effect.Effect<SessionHead, SessionMissing | SessionLogError>;
|
|
9
|
+
readonly list: (query: SessionListQuery) => Effect.Effect<ReadonlyArray<SessionHead>, SessionLogError>;
|
|
10
|
+
readonly read: (id: ConversationId, query: SessionReadQuery) => Effect.Effect<ReadonlyArray<SessionLogEvent>, SessionMissing | SessionLogError>;
|
|
11
|
+
/** Append events and/or replace the state, atomically, when the revision and the clock allow. */
|
|
12
|
+
readonly commit: (id: ConversationId, commit: SessionCommit) => Effect.Effect<SessionCommitted, RevisionConflict | LeaseExpired | SessionMissing | SessionLogError>;
|
|
13
|
+
/** Remove a session, its events and its children. Removing a missing session does nothing. */
|
|
14
|
+
readonly remove: (id: ConversationId) => Effect.Effect<void, SessionLogError>;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* STORAGE: the session log a host provides — one append-only log per
|
|
18
|
+
* session plus its head (see `session-log.entity.ts`). Everything above it
|
|
19
|
+
* (turns, leases, the inbox, memory) is the sessions plugin's; a backend
|
|
20
|
+
* only keeps the log, the head and the compare-and-swap, and passes
|
|
21
|
+
* `sessionLogConformance`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class SessionLog extends SessionLog_base {
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect, Option, Scope, Stream } from "effect";
|
|
3
|
+
import type { ConversationId } from "../domain/message.entity.js";
|
|
4
|
+
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
5
|
+
import type { JsonObject, SessionExists, SessionListCursor, SessionLogError, SessionLogEvent, SessionMissing } from "../session/session-log.entity.js";
|
|
6
|
+
import type { AdmittedTurn, BeginTurn, InboxFull, InboxItem, KeyConflict, NothingPending, ReservedKind, SessionAddress, SessionBusy, SessionPage, SessionView, TurnClosed, TurnDuplicate, TurnEnding, TurnRefused } from "../session/sessions.entity.js";
|
|
7
|
+
/** One event to record; the writer stamps the turn (or none, outside a turn). */
|
|
8
|
+
export interface TurnDraft {
|
|
9
|
+
readonly kind: string;
|
|
10
|
+
readonly data: JsonObject;
|
|
11
|
+
}
|
|
12
|
+
/** What a check-then-append decides: the events to record and the caller's result. */
|
|
13
|
+
export interface Decision<A> {
|
|
14
|
+
readonly drafts: ReadonlyArray<TurnDraft>;
|
|
15
|
+
readonly result: A;
|
|
16
|
+
}
|
|
17
|
+
/** A decision's result and the events it recorded, as stored. */
|
|
18
|
+
export interface Decided<A> {
|
|
19
|
+
readonly result: A;
|
|
20
|
+
readonly events: ReadonlyArray<SessionLogEvent>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The open turn's only way to write. Writes are queued and stored in queue
|
|
24
|
+
* order by one writer, consecutive appends in one commit, each commit
|
|
25
|
+
* guarded by the session's revision and the turn's lease: a write the
|
|
26
|
+
* session no longer accepts (cancelled, reaped, removed) closes the writer,
|
|
27
|
+
* and every later write fails with `turn.closed`.
|
|
28
|
+
*/
|
|
29
|
+
export interface TurnWriter {
|
|
30
|
+
readonly admitted: AdmittedTurn;
|
|
31
|
+
/** The `turn.started` event that opened the turn. */
|
|
32
|
+
readonly started: SessionLogEvent;
|
|
33
|
+
/** The session's events before this turn (a fork's parent first), of the given kinds: what memory is rebuilt from. */
|
|
34
|
+
readonly history: (kinds: ReadonlyArray<string>) => Effect.Effect<ReadonlyArray<SessionLogEvent>, HarnessError>;
|
|
35
|
+
/**
|
|
36
|
+
* A fresh durable snapshot including this turn (a fork's inherited history first). Flush queued writes before reading.
|
|
37
|
+
* With `after`, only this session's own events stored after that seq: the inherited history precedes them all.
|
|
38
|
+
*/
|
|
39
|
+
readonly snapshot: (kinds: ReadonlyArray<string>, after?: number) => Effect.Effect<ReadonlyArray<SessionLogEvent>, HarnessError>;
|
|
40
|
+
/** Queue events; returns once queued. */
|
|
41
|
+
readonly append: (drafts: ReadonlyArray<TurnDraft>) => Effect.Effect<void, HarnessError>;
|
|
42
|
+
/**
|
|
43
|
+
* Run `op` in queue order (after everything queued before it). When
|
|
44
|
+
* someone else closes the turn meanwhile, `op` is interrupted and the
|
|
45
|
+
* write fails with `turn.closed`.
|
|
46
|
+
*/
|
|
47
|
+
readonly write: <A, E>(op: Effect.Effect<A, E>) => Effect.Effect<A, E | HarnessError>;
|
|
48
|
+
/**
|
|
49
|
+
* Check, then append, atomically: `decide` sees the events others wrote
|
|
50
|
+
* during this turn and says what to record. When someone else writes
|
|
51
|
+
* before the commit, it decides again with their events.
|
|
52
|
+
*/
|
|
53
|
+
readonly transact: <A, E>(decide: (foreign: ReadonlyArray<SessionLogEvent>) => Effect.Effect<Decision<A>, E>) => Effect.Effect<Decided<A>, E | HarnessError>;
|
|
54
|
+
/** Wait until everything queued so far is stored. */
|
|
55
|
+
readonly flush: Effect.Effect<void, HarnessError>;
|
|
56
|
+
/**
|
|
57
|
+
* Close the turn: `turn.ended` is committed after every write queued
|
|
58
|
+
* before it. It is admitted like a write (so it waits while one waits for
|
|
59
|
+
* room in a full queue); from then on `append`, `write` and `transact` are
|
|
60
|
+
* refused, and `flush` still waits for what is queued. Calls while it runs
|
|
61
|
+
* share its result. A stored end, or a turn closed elsewhere, is final;
|
|
62
|
+
* after any other failure (a store error) writes are admitted again and a
|
|
63
|
+
* later end, the scope's own at the latest, tries again. Returns how many
|
|
64
|
+
* inbox items wait.
|
|
65
|
+
*/
|
|
66
|
+
readonly end: (ending: TurnEnding) => Effect.Effect<{
|
|
67
|
+
readonly pending: number;
|
|
68
|
+
}, HarnessError>;
|
|
69
|
+
/** Completes when someone else closed the turn; never when it ends by `end`. */
|
|
70
|
+
readonly closed: Effect.Effect<TurnClosed>;
|
|
71
|
+
}
|
|
72
|
+
declare const Sessions_base: Context.ServiceClass<Sessions, "efferent/Sessions", {
|
|
73
|
+
readonly create: (input: {
|
|
74
|
+
readonly owner: string;
|
|
75
|
+
readonly id?: ConversationId;
|
|
76
|
+
readonly origin?: string;
|
|
77
|
+
readonly meta?: JsonObject;
|
|
78
|
+
}) => Effect.Effect<SessionView, SessionExists | SessionLogError>;
|
|
79
|
+
/**
|
|
80
|
+
* A child session: with `inherit`, its history starts from the parent's
|
|
81
|
+
* last closed turn (a fork); without, it starts empty (a spawn).
|
|
82
|
+
*/
|
|
83
|
+
readonly fork: (parent: SessionAddress, input: {
|
|
84
|
+
readonly id?: ConversationId;
|
|
85
|
+
readonly origin: string;
|
|
86
|
+
readonly meta?: JsonObject;
|
|
87
|
+
readonly inherit: boolean;
|
|
88
|
+
}) => Effect.Effect<SessionView, SessionExists | SessionMissing | SessionLogError>;
|
|
89
|
+
readonly get: (address: SessionAddress) => Effect.Effect<SessionView, SessionMissing | SessionLogError>;
|
|
90
|
+
readonly list: (query: {
|
|
91
|
+
readonly owner: string;
|
|
92
|
+
readonly limit?: number;
|
|
93
|
+
readonly before?: SessionListCursor;
|
|
94
|
+
readonly parent?: ConversationId;
|
|
95
|
+
}) => Effect.Effect<SessionPage, SessionLogError>;
|
|
96
|
+
/** Remove a session and its children; an open turn on this instance is closed. */
|
|
97
|
+
readonly remove: (address: SessionAddress) => Effect.Effect<void, SessionMissing | SessionLogError>;
|
|
98
|
+
readonly read: (address: SessionAddress, query?: {
|
|
99
|
+
readonly after?: number;
|
|
100
|
+
readonly kinds?: ReadonlyArray<string>;
|
|
101
|
+
readonly limit?: number;
|
|
102
|
+
}) => Effect.Effect<ReadonlyArray<SessionLogEvent>, SessionMissing | SessionLogError>;
|
|
103
|
+
/** A signal after each commit this instance makes to the session (followers poll for the others). */
|
|
104
|
+
readonly changes: (address: SessionAddress) => Stream.Stream<void>;
|
|
105
|
+
/** The turn begun with this key, if any. */
|
|
106
|
+
readonly lookup: (address: SessionAddress, key: string) => Effect.Effect<Option.Option<number>, SessionMissing | SessionLogError>;
|
|
107
|
+
/** Check, then append outside a turn (a user's action on a page, a setting): decided again on a conflict. */
|
|
108
|
+
readonly transact: <A, E>(address: SessionAddress, decide: (view: SessionView) => Effect.Effect<Decision<A>, E>) => Effect.Effect<Decided<A>, E | ReservedKind | SessionMissing | SessionLogError>;
|
|
109
|
+
/** End exactly `turn` as cancelled, if it is the open one. */
|
|
110
|
+
readonly cancel: (address: SessionAddress, turn: number) => Effect.Effect<{
|
|
111
|
+
readonly cancelled: boolean;
|
|
112
|
+
readonly pending: number;
|
|
113
|
+
}, SessionMissing | SessionLogError>;
|
|
114
|
+
/**
|
|
115
|
+
* Open a turn, through the host's TurnAdmission. Its writer lives in the
|
|
116
|
+
* scope; a writer the scope closes unended ends as failed (or interrupted).
|
|
117
|
+
*/
|
|
118
|
+
readonly begin: (address: SessionAddress, input: BeginTurn) => Effect.Effect<TurnWriter, SessionBusy | TurnDuplicate | KeyConflict | NothingPending | TurnRefused | SessionMissing | SessionLogError, Scope.Scope>;
|
|
119
|
+
/** Put an item in the inbox (once per id); `pending` counts what waits after it. */
|
|
120
|
+
readonly deliver: (address: SessionAddress, item: InboxItem) => Effect.Effect<{
|
|
121
|
+
readonly delivered: boolean;
|
|
122
|
+
readonly pending: number;
|
|
123
|
+
}, InboxFull | SessionMissing | SessionLogError>;
|
|
124
|
+
/** Run inbox turns while items wait, the session is free and the host admits them, at most `maxTurns` (3). */
|
|
125
|
+
readonly drain: <E, R>(address: SessionAddress, run: (writer: TurnWriter) => Effect.Effect<void, E, R>, options?: {
|
|
126
|
+
readonly maxTurns?: number;
|
|
127
|
+
}) => Effect.Effect<{
|
|
128
|
+
readonly turns: number;
|
|
129
|
+
}, SessionMissing | SessionLogError, R>;
|
|
130
|
+
}>;
|
|
131
|
+
/**
|
|
132
|
+
* CONSUMPTION: sessions as hosts and turns use them, over the SessionLog a
|
|
133
|
+
* host provides. One turn is open per session at a time — a second begin is
|
|
134
|
+
* `SessionBusy` — and a turn's writes are refused once it is closed, on any
|
|
135
|
+
* instance. The inbox holds deliveries (a background task's result) for the
|
|
136
|
+
* turns that follow: whoever closes a turn, and whoever delivers, drains it.
|
|
137
|
+
* Reads never write: loading or following a session runs nothing.
|
|
138
|
+
*/
|
|
139
|
+
export declare class Sessions extends Sessions_base {
|
|
140
|
+
}
|
|
141
|
+
export {};
|
|
@@ -1,61 +1,23 @@
|
|
|
1
|
-
import { Context, Option, Schema } from "effect";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
budgetMillis: Schema.PropertySignature<":", Option.Option<number>, never, "?:", number | undefined, true, never>;
|
|
1
|
+
import { Context, Effect, Option, Schema } from "effect";
|
|
2
|
+
declare const EngineSettings_base: Schema.Class<EngineSettings, Schema.Struct<{
|
|
3
|
+
readonly model: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
|
|
4
|
+
readonly codeModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
|
|
5
|
+
readonly fastModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
|
|
6
|
+
readonly fallbackModel: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<string, string, never, never>>>;
|
|
7
|
+
readonly sandbox: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<boolean, boolean, never, never>>>;
|
|
8
|
+
readonly viMode: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<boolean, boolean, never, never>>>;
|
|
9
|
+
readonly maxAttempts: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<number, number, never, never>>>;
|
|
10
|
+
readonly budgetMillis: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<number, number, never, never>>>;
|
|
12
11
|
/** Selected after the model because the accepted levels are model-specific. */
|
|
13
|
-
reasoningEffort: Schema.
|
|
14
|
-
codeReasoningEffort: Schema.
|
|
15
|
-
fastReasoningEffort: Schema.
|
|
16
|
-
}
|
|
17
|
-
model: Schema.PropertySignature<":", Option.Option<string>, never, "?:", string | undefined, true, never>;
|
|
18
|
-
codeModel: Schema.PropertySignature<":", Option.Option<string>, never, "?:", string | undefined, true, never>;
|
|
19
|
-
fastModel: Schema.PropertySignature<":", Option.Option<string>, never, "?:", string | undefined, true, never>;
|
|
20
|
-
fallbackModel: Schema.PropertySignature<":", Option.Option<string>, never, "?:", string | undefined, true, never>;
|
|
21
|
-
sandbox: Schema.PropertySignature<":", Option.Option<boolean>, never, "?:", boolean | undefined, true, never>;
|
|
22
|
-
viMode: Schema.PropertySignature<":", Option.Option<boolean>, never, "?:", boolean | undefined, true, never>;
|
|
23
|
-
maxAttempts: Schema.PropertySignature<":", Option.Option<number>, never, "?:", number | undefined, true, never>;
|
|
24
|
-
budgetMillis: Schema.PropertySignature<":", Option.Option<number>, never, "?:", number | undefined, true, never>;
|
|
25
|
-
/** Selected after the model because the accepted levels are model-specific. */
|
|
26
|
-
reasoningEffort: Schema.PropertySignature<":", Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">, never, "?:", "none" | "low" | "medium" | "high" | "xhigh" | "max" | undefined, true, never>;
|
|
27
|
-
codeReasoningEffort: Schema.PropertySignature<":", Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">, never, "?:", "none" | "low" | "medium" | "high" | "xhigh" | "max" | undefined, true, never>;
|
|
28
|
-
fastReasoningEffort: Schema.PropertySignature<":", Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">, never, "?:", "none" | "low" | "medium" | "high" | "xhigh" | "max" | undefined, true, never>;
|
|
29
|
-
}>, never, {
|
|
30
|
-
readonly model?: Option.Option<string>;
|
|
31
|
-
} & {
|
|
32
|
-
readonly codeModel?: Option.Option<string>;
|
|
33
|
-
} & {
|
|
34
|
-
readonly fastModel?: Option.Option<string>;
|
|
35
|
-
} & {
|
|
36
|
-
readonly fallbackModel?: Option.Option<string>;
|
|
37
|
-
} & {
|
|
38
|
-
readonly sandbox?: Option.Option<boolean>;
|
|
39
|
-
} & {
|
|
40
|
-
readonly viMode?: Option.Option<boolean>;
|
|
41
|
-
} & {
|
|
42
|
-
readonly maxAttempts?: Option.Option<number>;
|
|
43
|
-
} & {
|
|
44
|
-
readonly budgetMillis?: Option.Option<number>;
|
|
45
|
-
} & {
|
|
46
|
-
readonly reasoningEffort?: Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">;
|
|
47
|
-
} & {
|
|
48
|
-
readonly codeReasoningEffort?: Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">;
|
|
49
|
-
} & {
|
|
50
|
-
readonly fastReasoningEffort?: Option.Option<"none" | "low" | "medium" | "high" | "xhigh" | "max">;
|
|
51
|
-
}, {}, {}>;
|
|
12
|
+
readonly reasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
|
|
13
|
+
readonly codeReasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
|
|
14
|
+
readonly fastReasoningEffort: Schema.withConstructorDefault<Schema.OptionFromOptional<Schema.Codec<"none" | "low" | "medium" | "high" | "xhigh" | "max", "none" | "low" | "medium" | "high" | "xhigh" | "max", never, never>>>;
|
|
15
|
+
}>, {}>;
|
|
52
16
|
export declare class EngineSettings extends EngineSettings_base {
|
|
53
17
|
}
|
|
54
|
-
declare const SettingsError_base: Schema.
|
|
55
|
-
readonly
|
|
56
|
-
}
|
|
57
|
-
message: typeof Schema.String;
|
|
58
|
-
}>;
|
|
18
|
+
declare const SettingsError_base: Schema.Class<SettingsError, Schema.TaggedStruct<"SettingsError", {
|
|
19
|
+
readonly message: Schema.String;
|
|
20
|
+
}>, import("effect/Cause").YieldableError>;
|
|
59
21
|
export declare class SettingsError extends SettingsError_base {
|
|
60
22
|
}
|
|
61
23
|
/** The three model roles a selection can be persisted under. */
|
|
@@ -64,7 +26,7 @@ export type ModelRole = "general" | "code" | "fast";
|
|
|
64
26
|
* typo can never land a dead key in the user's config. */
|
|
65
27
|
export declare const SETTINGS_KEYS: readonly ["fallbackModel", "sandbox", "viMode", "maxAttempts", "budgetMillis", "reasoningEffort", "codeReasoningEffort", "fastReasoningEffort"];
|
|
66
28
|
export type SettingsKey = (typeof SETTINGS_KEYS)[number];
|
|
67
|
-
declare const SettingsStore_base: Context.
|
|
29
|
+
declare const SettingsStore_base: Context.ServiceClass<SettingsStore, "@xandreed/core/SettingsStore", {
|
|
68
30
|
readonly load: Effect.Effect<EngineSettings, SettingsError>;
|
|
69
31
|
/** Persist one role's model selection (the human's `:model` action);
|
|
70
32
|
* `None` clears the role so it falls back to its default again. */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Context, Option, Schema } from "effect";
|
|
1
|
+
import { Context, Effect, Option, Schema } from "effect";
|
|
2
2
|
import { ReasoningEffort } from "../domain/model-call-policy.entity.js";
|
|
3
|
-
const optionField = (schema) => Schema.
|
|
3
|
+
const optionField = (schema) => Schema.OptionFromOptional(schema).pipe(Schema.withConstructorDefault(Effect.succeed(Option.none())));
|
|
4
4
|
|
|
5
5
|
export class EngineSettings extends Schema.Class("EngineSettings")({
|
|
6
6
|
model: optionField(Schema.String),
|
|
@@ -32,5 +32,5 @@ export const SETTINGS_KEYS = [
|
|
|
32
32
|
"fastReasoningEffort"
|
|
33
33
|
];
|
|
34
34
|
|
|
35
|
-
export class SettingsStore extends Context.
|
|
35
|
+
export class SettingsStore extends Context.Service()("@xandreed/core/SettingsStore") {
|
|
36
36
|
}
|
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
import { Context, Schema } from "effect";
|
|
2
2
|
import type { Effect } from "effect";
|
|
3
|
-
declare const ShellError_base: Schema.
|
|
4
|
-
readonly
|
|
5
|
-
}
|
|
6
|
-
message: typeof Schema.String;
|
|
7
|
-
}>;
|
|
3
|
+
declare const ShellError_base: Schema.Class<ShellError, Schema.TaggedStruct<"ShellError", {
|
|
4
|
+
readonly message: Schema.String;
|
|
5
|
+
}>, import("effect/Cause").YieldableError>;
|
|
8
6
|
export declare class ShellError extends ShellError_base {
|
|
9
7
|
}
|
|
10
|
-
declare const ShellResult_base: Schema.Class<ShellResult, {
|
|
11
|
-
stdout:
|
|
12
|
-
stderr:
|
|
13
|
-
exitCode:
|
|
14
|
-
}
|
|
15
|
-
stdout: typeof Schema.String;
|
|
16
|
-
stderr: typeof Schema.String;
|
|
17
|
-
exitCode: typeof Schema.Number;
|
|
18
|
-
}>, never, {
|
|
19
|
-
readonly stdout: string;
|
|
20
|
-
} & {
|
|
21
|
-
readonly stderr: string;
|
|
22
|
-
} & {
|
|
23
|
-
readonly exitCode: number;
|
|
24
|
-
}, {}, {}>;
|
|
8
|
+
declare const ShellResult_base: Schema.Class<ShellResult, Schema.Struct<{
|
|
9
|
+
readonly stdout: Schema.String;
|
|
10
|
+
readonly stderr: Schema.String;
|
|
11
|
+
readonly exitCode: Schema.Number;
|
|
12
|
+
}>, {}>;
|
|
25
13
|
export declare class ShellResult extends ShellResult_base {
|
|
26
14
|
}
|
|
27
|
-
declare const Shell_base: Context.
|
|
15
|
+
declare const Shell_base: Context.ServiceClass<Shell, "@xandreed/core/Shell", {
|
|
28
16
|
readonly exec: (command: string, options?: {
|
|
29
17
|
readonly cwd?: string;
|
|
30
18
|
readonly timeoutMs?: number;
|
package/dist/ports/shell.port.js
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect, Option } from "effect";
|
|
3
|
+
import type { LanguageModel, Prompt, Tool } from "effect/ai";
|
|
4
|
+
import type { AgentMessage } from "../domain/message.entity.js";
|
|
5
|
+
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
6
|
+
import type { LogEntry } from "../memory/memory-log.entity.js";
|
|
7
|
+
import type { CompletionVerdict } from "../turn/turn-event.entity.js";
|
|
8
|
+
import type { InitialBatch, StepInfo, ToolChoice } from "./capability.port.js";
|
|
9
|
+
import type { RunTools } from "./tool-registry.port.js";
|
|
10
|
+
import type { TurnEventsService, TurnTasksService } from "./turn-events.port.js";
|
|
11
|
+
export interface LoopLimits {
|
|
12
|
+
/** A ceiling, not a target: a run ends when the model stops calling tools. */
|
|
13
|
+
readonly maxSteps: number;
|
|
14
|
+
readonly toolConcurrency: number;
|
|
15
|
+
readonly streaming: boolean;
|
|
16
|
+
/** A model stop does not end the run while the completion verdict is incomplete. */
|
|
17
|
+
readonly requireCompletion: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Host wording for the loop's own corrective turns. */
|
|
20
|
+
export interface Correctives {
|
|
21
|
+
readonly malformed: (tools: ReadonlyArray<string>, description: string) => string;
|
|
22
|
+
readonly incomplete: string;
|
|
23
|
+
}
|
|
24
|
+
/** Everything one provider request needs, prepared by the turn. */
|
|
25
|
+
export interface StepPlan {
|
|
26
|
+
/** The step's model, resolved once for the step (`resolveModelRequest`); None: the LanguageModel in the turn's services. */
|
|
27
|
+
readonly model: Option.Option<LanguageModel.LanguageModel>;
|
|
28
|
+
readonly system: string;
|
|
29
|
+
readonly messages: ReadonlyArray<AgentMessage>;
|
|
30
|
+
readonly toolChoice: Option.Option<ToolChoice>;
|
|
31
|
+
}
|
|
32
|
+
export interface StepRequest {
|
|
33
|
+
readonly tools: RunTools;
|
|
34
|
+
/** What the tool handlers run with: the turn's services (its LanguageModel included) and the registry's handlers. */
|
|
35
|
+
readonly handlers: Context.Context<never>;
|
|
36
|
+
readonly limits: LoopLimits;
|
|
37
|
+
/** A host-planned first batch, run as step zero without a provider call. */
|
|
38
|
+
readonly initial: Option.Option<InitialBatch>;
|
|
39
|
+
readonly plan: (step: StepInfo) => Effect.Effect<StepPlan, HarnessError>;
|
|
40
|
+
/**
|
|
41
|
+
* Validate an actual dispatch against a fresh durable derivation. Run immediately before each provider attempt,
|
|
42
|
+
* including a streaming fallback; a failed check fails the step (a streamed step does not fall back).
|
|
43
|
+
*/
|
|
44
|
+
readonly dispatch: (step: number, request: ModelDispatch) => Effect.Effect<void, HarnessError>;
|
|
45
|
+
/** Persist a step's appended messages; returns their log entries. */
|
|
46
|
+
readonly record: (step: number, tail: ReadonlyArray<AgentMessage>) => Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
47
|
+
readonly completion: (step: StepInfo) => Effect.Effect<CompletionVerdict, HarnessError>;
|
|
48
|
+
readonly steering: Effect.Effect<Option.Option<string>, HarnessError>;
|
|
49
|
+
readonly correctives: Option.Option<Correctives>;
|
|
50
|
+
readonly events: TurnEventsService;
|
|
51
|
+
readonly tasks: TurnTasksService;
|
|
52
|
+
readonly cacheKey: Option.Option<string>;
|
|
53
|
+
}
|
|
54
|
+
export interface ModelDispatch {
|
|
55
|
+
readonly prompt: Prompt.Prompt;
|
|
56
|
+
readonly tools: ReadonlyArray<Tool.Any>;
|
|
57
|
+
readonly toolChoice: unknown;
|
|
58
|
+
readonly model: LanguageModel.LanguageModel;
|
|
59
|
+
}
|
|
60
|
+
export interface RunResult {
|
|
61
|
+
readonly outcome: "completed" | "partial";
|
|
62
|
+
readonly reason: "completed" | "step-cap" | "degenerate-loop";
|
|
63
|
+
readonly text: string;
|
|
64
|
+
readonly steps: number;
|
|
65
|
+
}
|
|
66
|
+
declare const StepLoop_base: Context.ServiceClass<StepLoop, "efferent/StepLoop", {
|
|
67
|
+
readonly id: string;
|
|
68
|
+
readonly version: string;
|
|
69
|
+
readonly run: (request: StepRequest) => Effect.Effect<RunResult, HarnessError>;
|
|
70
|
+
}>;
|
|
71
|
+
/**
|
|
72
|
+
* THE step loop: iterate provider steps until the model stops, the
|
|
73
|
+
* completion verdict holds, or a limit is hit. Contract (see
|
|
74
|
+
* `stepLoopConformance`): per step `step.started` < `tool.*` < `step.ended`
|
|
75
|
+
* (after the tail is recorded) < `completion.evaluated`; a planned batch
|
|
76
|
+
* makes no provider call; a forced tool choice is honoured; a verdict
|
|
77
|
+
* awaiting tasks joins them and is evaluated once more; no provider call
|
|
78
|
+
* follows a complete verdict.
|
|
79
|
+
* Every real provider attempt runs `request.dispatch` immediately before
|
|
80
|
+
* invoking the model; a failed durable check prevents the call. Planned
|
|
81
|
+
* batches skip that hook because they make no provider request.
|
|
82
|
+
*/
|
|
83
|
+
export declare class StepLoop extends StepLoop_base {
|
|
84
|
+
}
|
|
85
|
+
export {};
|