@xandreed/core 0.13.0 → 0.14.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.functions.d.ts +34 -0
- package/dist/conformance.functions.js +25 -0
- package/dist/domain/bash.entity.d.ts +82 -0
- package/dist/domain/bash.entity.functions.d.ts +17 -0
- package/dist/domain/bash.entity.functions.js +26 -0
- package/dist/domain/bash.entity.functions.test.d.ts +1 -0
- package/dist/domain/bash.entity.js +30 -0
- package/dist/domain/file-system.entity.d.ts +91 -0
- package/dist/domain/file-system.entity.functions.d.ts +18 -0
- package/dist/domain/file-system.entity.functions.js +30 -0
- package/dist/domain/file-system.entity.js +37 -0
- package/dist/domain/loop-event.entity.d.ts +9 -0
- package/dist/domain/media.entity.d.ts +79 -0
- package/dist/domain/media.entity.functions.d.ts +76 -0
- package/dist/domain/media.entity.functions.js +110 -0
- package/dist/domain/media.entity.js +38 -0
- package/dist/domain/media.entity.test.d.ts +1 -0
- package/dist/domain/message.entity.d.ts +157 -5
- package/dist/domain/message.entity.js +8 -4
- package/dist/domain/model-catalog.entity.d.ts +2 -0
- package/dist/domain/model-catalog.entity.js +2 -1
- package/dist/domain/token-usage.entity.d.ts +45 -1
- package/dist/domain/token-usage.entity.functions.d.ts +30 -1
- package/dist/domain/token-usage.entity.functions.js +24 -4
- package/dist/domain/token-usage.entity.js +19 -2
- package/dist/domain/token-usage.entity.test.d.ts +1 -0
- package/dist/harness/capability.entity.functions.js +2 -1
- package/dist/harness/plugin.adapter.d.ts +3 -0
- package/dist/harness/plugin.adapter.js +7 -1
- package/dist/harness/skill-files.entity.d.ts +101 -0
- package/dist/harness/skill-files.entity.functions.d.ts +58 -0
- package/dist/harness/skill-files.entity.functions.js +150 -0
- package/dist/harness/skill-files.entity.functions.test.d.ts +1 -0
- package/dist/harness/skill-files.entity.js +25 -0
- package/dist/index.d.ts +48 -8
- package/dist/index.js +67 -6
- package/dist/loop/mapping.d.ts +12 -6
- package/dist/loop/mapping.js +30 -6
- package/dist/loop/stepContext.d.ts +8 -0
- package/dist/loop/stepContext.js +1 -1
- package/dist/loop/traceContent.d.ts +29 -0
- package/dist/loop/traceContent.js +4 -0
- package/dist/loop/traceContent.test.d.ts +1 -0
- package/dist/memory/memory-log.entity.d.ts +152 -14
- package/dist/memory/memory-log.entity.functions.d.ts +35 -5
- package/dist/memory/memory-log.entity.functions.js +59 -20
- package/dist/memory/memory-log.entity.js +19 -6
- package/dist/memory/memory-session.js +10 -6
- package/dist/memory/memory.conformance.d.ts +8 -1
- package/dist/memory/memory.conformance.js +32 -0
- package/dist/models/auth-store.conformance.d.ts +13 -0
- package/dist/models/auth-store.conformance.js +73 -0
- package/dist/models/auth-store.conformance.test.d.ts +1 -0
- package/dist/models/model-catalog.conformance.d.ts +15 -0
- package/dist/models/model-catalog.conformance.js +27 -0
- package/dist/models/model-catalog.conformance.test.d.ts +1 -0
- package/dist/models/settings-store.conformance.d.ts +26 -0
- package/dist/models/settings-store.conformance.js +80 -0
- package/dist/models/settings-store.conformance.test.d.ts +1 -0
- package/dist/ports/activity.port.d.ts +35 -0
- package/dist/ports/activity.port.js +7 -0
- package/dist/ports/auth-store.port.d.ts +7 -5
- package/dist/ports/bash.port.d.ts +22 -0
- package/dist/ports/bash.port.js +4 -0
- package/dist/ports/capability.port.d.ts +11 -1
- package/dist/ports/file-system.port.d.ts +44 -15
- package/dist/ports/file-system.port.js +1 -7
- package/dist/ports/memory.port.d.ts +13 -1
- package/dist/ports/model-catalog.port.d.ts +4 -1
- package/dist/ports/run-context.port.d.ts +6 -1
- package/dist/ports/session-log.port.d.ts +4 -1
- package/dist/ports/sessions.port.d.ts +35 -6
- package/dist/ports/settings-store.port.d.ts +11 -7
- package/dist/ports/step-loop.port.d.ts +30 -2
- package/dist/ports/tasks.port.d.ts +5 -1
- package/dist/ports/turn-admission.port.d.ts +8 -2
- package/dist/ports/turn-events.port.d.ts +8 -1
- package/dist/ports/turn-scope.port.d.ts +19 -1
- package/dist/ports/turn.port.d.ts +70 -5
- package/dist/ports/utility-llm.port.d.ts +2 -0
- package/dist/session/activity.entity.d.ts +42 -0
- package/dist/session/activity.entity.functions.d.ts +21 -0
- package/dist/session/activity.entity.functions.js +23 -0
- package/dist/session/activity.entity.functions.test.d.ts +1 -0
- package/dist/session/activity.entity.js +15 -0
- package/dist/session/chassis.js +2 -1
- package/dist/session/session-event.entity.d.ts +68 -6
- package/dist/session/session-event.entity.functions.d.ts +34 -2
- package/dist/session/session-event.entity.functions.js +54 -16
- package/dist/session/session-event.entity.js +19 -2
- package/dist/session/session-log.conformance.d.ts +4 -3
- package/dist/session/session-log.conformance.js +16 -14
- package/dist/session/session-log.recovery.conformance.d.ts +40 -0
- package/dist/session/session-log.recovery.conformance.js +143 -0
- package/dist/session/session-log.recovery.conformance.test.d.ts +1 -0
- package/dist/session/sessions.conformance.d.ts +79 -0
- package/dist/session/sessions.conformance.js +355 -0
- package/dist/session/sessions.entity.d.ts +36 -3
- package/dist/session/sessions.entity.functions.d.ts +42 -0
- package/dist/session/sessions.entity.functions.js +26 -0
- package/dist/session/sessions.entity.js +17 -4
- package/dist/session/sessions.entity.test.d.ts +1 -0
- package/dist/session/tasks.conformance.d.ts +70 -0
- package/dist/session/tasks.conformance.js +213 -0
- package/dist/session/tasks.conformance.test.d.ts +1 -0
- package/dist/turn/model-request.entity.d.ts +4 -0
- package/dist/turn/model-request.entity.js +7 -2
- package/dist/turn/step-loop.conformance.d.ts +4 -1
- package/dist/turn/step-loop.conformance.js +73 -7
- package/dist/turn/tool-registry.conformance.d.ts +38 -0
- package/dist/turn/tool-registry.conformance.js +206 -0
- package/dist/turn/turn-bus.js +4 -3
- package/dist/turn/turn-event.entity.d.ts +134 -34
- package/dist/turn/turn-event.entity.functions.d.ts +11 -0
- package/dist/turn/turn-event.entity.functions.js +9 -1
- package/dist/turn/turn-event.entity.js +76 -3
- package/dist/turn/turn-event.entity.test.d.ts +1 -0
- package/dist/turn/turn-lifecycle.d.ts +46 -8
- package/dist/turn/turn-lifecycle.js +33 -3
- package/dist/turn/turn-lifecycle.test.d.ts +1 -0
- package/dist/turn/turn-run.d.ts +15 -3
- package/dist/turn/turn-run.js +37 -9
- package/dist/turn/turn.adapter.d.ts +6 -5
- package/dist/turn/turn.adapter.js +15 -3
- package/dist/turn/turn.conformance.d.ts +11 -2
- package/dist/turn/turn.conformance.js +63 -2
- package/dist/turn/user-message.entity.d.ts +14 -4
- package/dist/turn/user-message.entity.functions.d.ts +21 -0
- package/dist/turn/user-message.entity.functions.js +24 -0
- package/dist/turn/user-message.entity.js +6 -8
- package/dist/turn/user-message.entity.test.d.ts +1 -0
- package/dist/util/glob.d.ts +30 -0
- package/dist/util/glob.js +91 -0
- package/dist/util/glob.test.d.ts +1 -0
- package/dist/workspace/bash.conformance.d.ts +37 -0
- package/dist/workspace/bash.conformance.js +120 -0
- package/dist/workspace/bash.conformance.test.d.ts +1 -0
- package/dist/workspace/file-system.conformance.d.ts +38 -0
- package/dist/workspace/file-system.conformance.js +254 -0
- package/dist/workspace/file-system.conformance.test.d.ts +1 -0
- package/dist/workspace/file-system.memory.adapter.d.ts +23 -0
- package/dist/workspace/file-system.memory.adapter.js +132 -0
- package/package.json +1 -1
- package/dist/harness/skill-files.d.ts +0 -17
- package/dist/harness/skill-files.js +0 -25
- package/dist/ports/shell.port.d.ts +0 -32
- package/dist/ports/shell.port.js +0 -16
|
@@ -32,16 +32,18 @@ declare const AuthStore_base: Context.ServiceClass<AuthStore, "@xandreed/core/Au
|
|
|
32
32
|
readonly all: Effect.Effect<ReadonlyMap<string, Credential>, AuthError>;
|
|
33
33
|
readonly get: (p: ProviderId) => Effect.Effect<Option.Option<Credential>, AuthError>;
|
|
34
34
|
readonly resolveKey: (p: ProviderId) => Effect.Effect<Option.Option<Redacted.Redacted<string>>, AuthError>;
|
|
35
|
-
/** Persist a credential (
|
|
35
|
+
/** Persist a credential (a login). */
|
|
36
36
|
readonly set: (p: ProviderId, credential: Credential) => Effect.Effect<void, AuthError>;
|
|
37
|
-
/** Remove a provider's credential everywhere it is stored (
|
|
37
|
+
/** Remove a provider's credential everywhere it is stored (a logout). */
|
|
38
38
|
readonly remove: (p: ProviderId) => Effect.Effect<void, AuthError>;
|
|
39
39
|
}>;
|
|
40
40
|
/**
|
|
41
41
|
* The credential store, read lazily per request: `resolveKey` returns a
|
|
42
|
-
* usable secret (refreshing
|
|
43
|
-
* so a credential added mid-session
|
|
44
|
-
* restart. `None` means the provider
|
|
42
|
+
* usable secret (refreshing a near-expiry OAuth token first, and persisting
|
|
43
|
+
* it where the store keeps credentials), so a credential added mid-session
|
|
44
|
+
* takes effect on the next call with no restart. `None` means the provider
|
|
45
|
+
* is not configured. `authStoreConformance` checks a store against this
|
|
46
|
+
* contract.
|
|
45
47
|
*/
|
|
46
48
|
export declare class AuthStore extends AuthStore_base {
|
|
47
49
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import type { Effect, Stream } from "effect";
|
|
3
|
+
import type { BashError, BashEvent, BashOptions, BashResult } from "../domain/bash.entity.js";
|
|
4
|
+
declare const Bash_base: Context.ServiceClass<Bash, "@xandreed/core/Bash", {
|
|
5
|
+
/** Output chunks as they arrive, then exactly one `BashExit`. */
|
|
6
|
+
readonly stream: (command: string, options: BashOptions) => Stream.Stream<BashEvent, BashError>;
|
|
7
|
+
/** The whole output and how the command ended (`collectBashResult` over `stream`). */
|
|
8
|
+
readonly exec: (command: string, options: BashOptions) => Effect.Effect<BashResult, BashError>;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Commands run with `bash -c`, each in a process group of its own. A
|
|
12
|
+
* non-zero exit, a signal and a timeout are results the caller reads,
|
|
13
|
+
* never errors: `BashError` means the command could not run at all. When a
|
|
14
|
+
* command times out or its caller stops waiting (the stream or the `exec`
|
|
15
|
+
* is interrupted), the adapter kills its whole process group, so what it
|
|
16
|
+
* started in the background goes with it; an adapter may also do that when
|
|
17
|
+
* the command exits. The environment is built with `resolveBashEnv`.
|
|
18
|
+
* `bashConformance` is the contract as runnable checks.
|
|
19
|
+
*/
|
|
20
|
+
export declare class Bash extends Bash_base {
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect, Option } from "effect";
|
|
3
3
|
import type { LanguageModel, Tool } from "effect/ai";
|
|
4
|
+
import type { Media } from "../domain/media.entity.js";
|
|
4
5
|
import type { AgentMessage } from "../domain/message.entity.js";
|
|
5
6
|
import type { TokenUsage } from "../domain/token-usage.entity.js";
|
|
6
7
|
import type { PromptTier, SkillDefinition, ToolAnnotations } from "../harness/capability.entity.js";
|
|
@@ -38,9 +39,16 @@ export interface ToolViewDefinition<Result, Params> {
|
|
|
38
39
|
/** The older-turn form; None keeps `render`'s text. */
|
|
39
40
|
readonly compact: Option.Option<(result: Result, params: Params) => string>;
|
|
40
41
|
readonly subjects: (result: Result, params: Params) => ReadonlyArray<Subject>;
|
|
41
|
-
/** Files and images the result
|
|
42
|
+
/** Files and images the result points to by URL, kept by reference (shown as reference lines). */
|
|
42
43
|
readonly artifacts: (result: Result, params: Params) => ReadonlyArray<ArtifactRef>;
|
|
43
44
|
readonly digest: Option.Option<DigestDefinition<Result, Params>>;
|
|
45
|
+
/**
|
|
46
|
+
* The images the model is sent with the result: `Media` values the result
|
|
47
|
+
* holds (one it does not hold is ignored). None: every image it holds.
|
|
48
|
+
* A tool returns images as `Media` values in its success value;
|
|
49
|
+
* `Tool.toModelOutput` is not used.
|
|
50
|
+
*/
|
|
51
|
+
readonly media: Option.Option<(result: Result, params: Params) => ReadonlyArray<Media>>;
|
|
44
52
|
}
|
|
45
53
|
/** The view as an author writes it; optional parts default in `defineTool`. */
|
|
46
54
|
export interface ToolViewInput<Result, Params> {
|
|
@@ -50,6 +58,8 @@ export interface ToolViewInput<Result, Params> {
|
|
|
50
58
|
readonly subjects?: (result: Result, params: Params) => ReadonlyArray<Subject>;
|
|
51
59
|
readonly artifacts?: (result: Result, params: Params) => ReadonlyArray<ArtifactRef>;
|
|
52
60
|
readonly digest?: DigestDefinition<Result, Params>;
|
|
61
|
+
/** The images among the result's the model is sent with it; omitted: every image the result holds. */
|
|
62
|
+
readonly media?: (result: Result, params: Params) => ReadonlyArray<Media>;
|
|
53
63
|
}
|
|
54
64
|
/** A typed tool definition as its author writes it (see `defineTool`). */
|
|
55
65
|
export interface ToolDefinition<T extends Tool.Any, R> {
|
|
@@ -1,24 +1,53 @@
|
|
|
1
|
-
import { Context
|
|
1
|
+
import { Context } from "effect";
|
|
2
2
|
import type { Effect } from "effect";
|
|
3
|
-
|
|
4
|
-
readonly path: Schema.String;
|
|
5
|
-
readonly message: Schema.String;
|
|
6
|
-
}>, import("effect/Cause").YieldableError>;
|
|
7
|
-
export declare class FsError extends FsError_base {
|
|
8
|
-
}
|
|
3
|
+
import type { DirEntry, FileInfo, FsError, GlobOptions, GlobResult, ReadRange, RecursiveOptions, StatOptions, WriteOptions } from "../domain/file-system.entity.js";
|
|
9
4
|
declare const FileSystem_base: Context.ServiceClass<FileSystem, "@xandreed/core/FileSystem", {
|
|
5
|
+
/** A file's text, decoded as UTF-8. */
|
|
10
6
|
readonly read: (path: string) => Effect.Effect<string, FsError>;
|
|
11
|
-
|
|
7
|
+
/** A file's bytes, or a range of them; a range past the end returns what there is. */
|
|
8
|
+
readonly readBytes: (path: string, range?: ReadRange) => Effect.Effect<Uint8Array, FsError>;
|
|
9
|
+
/** Create or replace a file (text is written as UTF-8). Without `createParents`, a missing parent fails with `NotFound`. */
|
|
10
|
+
readonly write: (path: string, content: string | Uint8Array, options?: WriteOptions) => Effect.Effect<void, FsError>;
|
|
11
|
+
/** Add to the end of a file, creating it when missing. */
|
|
12
|
+
readonly append: (path: string, content: string | Uint8Array, options?: WriteOptions) => Effect.Effect<void, FsError>;
|
|
13
|
+
/**
|
|
14
|
+
* Move a file, directory or link (the link itself, not its target); an
|
|
15
|
+
* existing file at `to` is replaced. A failure names the side that caused
|
|
16
|
+
* it: `from` when it is missing, `to` for a missing parent there or what
|
|
17
|
+
* is in the way (`IsDirectory`, `NotDirectory`, `NotEmpty`).
|
|
18
|
+
*/
|
|
19
|
+
readonly rename: (from: string, to: string) => Effect.Effect<void, FsError>;
|
|
20
|
+
readonly stat: (path: string, options?: StatOptions) => Effect.Effect<FileInfo, FsError>;
|
|
21
|
+
/** Whether the path exists (a link whose target is missing does not). A missing path is `false`, not an error. */
|
|
12
22
|
readonly exists: (path: string) => Effect.Effect<boolean, FsError>;
|
|
13
|
-
|
|
14
|
-
readonly
|
|
15
|
-
/**
|
|
23
|
+
/** A directory's entries, sorted by name (code-unit order), links not followed. */
|
|
24
|
+
readonly list: (dir: string) => Effect.Effect<ReadonlyArray<DirEntry>, FsError>;
|
|
25
|
+
/** The paths under `options.cwd` the pattern matches (`*`, `**`, `?`, `[...]`, `{a,b}`); links are never entered. */
|
|
26
|
+
readonly glob: (pattern: string, options: GlobOptions) => Effect.Effect<GlobResult, FsError>;
|
|
27
|
+
/** Create a directory. Without `recursive`, an existing path fails with `Exists` and a missing parent with `NotFound`; with it, existing directories are fine. */
|
|
28
|
+
readonly mkdir: (dir: string, options?: RecursiveOptions) => Effect.Effect<void, FsError>;
|
|
29
|
+
/** The canonical absolute path, every symbolic link resolved. */
|
|
16
30
|
readonly realPath: (path: string) => Effect.Effect<string, FsError>;
|
|
17
|
-
/**
|
|
18
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Delete a file, a link (not its target) or a directory. A missing path
|
|
33
|
+
* is a no-op. Without `recursive`, an empty directory is removed and one
|
|
34
|
+
* with entries fails with `NotEmpty`. Links in the parent are followed
|
|
35
|
+
* and the last name never is, trailing slash or not (`link/` removes
|
|
36
|
+
* the link). The root, and a path whose last segment is `.` or `..`,
|
|
37
|
+
* fail with `Invalid`.
|
|
38
|
+
*/
|
|
39
|
+
readonly remove: (path: string, options?: RecursiveOptions) => Effect.Effect<void, FsError>;
|
|
19
40
|
}>;
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
41
|
+
/**
|
|
42
|
+
* The file system agent tools work through. Paths are absolute (the port
|
|
43
|
+
* does no cwd magic) and POSIX; every failure is an `FsError` whose
|
|
44
|
+
* `reason` is the same on every backend. Calls follow symbolic links,
|
|
45
|
+
* except `list` (which reports links as `symlink`), `remove` (which removes
|
|
46
|
+
* the link), `rename` (which moves the link, not its target) and `stat`
|
|
47
|
+
* with `followSymlinks: false`. `fileSystemConformance`
|
|
48
|
+
* is the contract as runnable checks; `FileSystemMemoryLive` is the
|
|
49
|
+
* in-memory backend.
|
|
50
|
+
*/
|
|
22
51
|
export declare class FileSystem extends FileSystem_base {
|
|
23
52
|
}
|
|
24
53
|
export {};
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import { Context
|
|
2
|
-
|
|
3
|
-
export class FsError extends Schema.TaggedError()("FsError", {
|
|
4
|
-
path: Schema.String,
|
|
5
|
-
message: Schema.String
|
|
6
|
-
}) {
|
|
7
|
-
}
|
|
1
|
+
import { Context } from "effect";
|
|
8
2
|
|
|
9
3
|
export class FileSystem extends Context.Service()("@xandreed/core/FileSystem") {
|
|
10
4
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect, Option, Scope } from "effect";
|
|
3
|
+
import type { MediaSlot } from "../domain/media.entity.js";
|
|
3
4
|
import type { AgentMessage, ConversationId } from "../domain/message.entity.js";
|
|
4
5
|
import type { TokenUsage } from "../domain/token-usage.entity.js";
|
|
5
6
|
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
@@ -19,6 +20,13 @@ export interface ToolView {
|
|
|
19
20
|
readonly subjects: ReadonlyArray<Subject>;
|
|
20
21
|
readonly artifacts: ReadonlyArray<ArtifactRef>;
|
|
21
22
|
readonly pinned: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The images of the encoded result the model is sent with it, where they
|
|
25
|
+
* are in it (`mediaSlotsOf`). Memory checks each one when it records the
|
|
26
|
+
* result (`toolResultMedia`): an image that fails, or one over
|
|
27
|
+
* `MEDIA_LIMITS.toolResultImages`, is a label line in the stored view.
|
|
28
|
+
*/
|
|
29
|
+
readonly media?: ReadonlyArray<MediaSlot>;
|
|
22
30
|
}
|
|
23
31
|
/** What the digester returns: the item keys to keep, or a summary. */
|
|
24
32
|
export interface DigestOutcome {
|
|
@@ -72,7 +80,11 @@ export interface MemoryReader {
|
|
|
72
80
|
export interface MaintainSignal {
|
|
73
81
|
readonly phase: "turn-start" | "step";
|
|
74
82
|
readonly lastUsage: Option.Option<TokenUsage>;
|
|
75
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* Tokens available to the messages, at least 1: at `step`, what the system
|
|
85
|
+
* prompt and the active tool schemas leave of the run's budget; at
|
|
86
|
+
* `turn-start`, the run's whole budget (nothing is built yet).
|
|
87
|
+
*/
|
|
76
88
|
readonly budgetTokens: number;
|
|
77
89
|
readonly views: ToolViews;
|
|
78
90
|
}
|
|
@@ -4,7 +4,10 @@ import type { ModelCatalogEntry } from "../domain/model-catalog.entity.js";
|
|
|
4
4
|
declare const ModelCatalog_base: Context.ServiceClass<ModelCatalog, "@xandreed/core/ModelCatalog", {
|
|
5
5
|
readonly list: Effect.Effect<ReadonlyArray<ModelCatalogEntry>>;
|
|
6
6
|
}>;
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Provider-neutral discovery of models usable by configured adapters.
|
|
9
|
+
* `modelCatalogConformance` checks a catalog against this contract.
|
|
10
|
+
*/
|
|
8
11
|
export declare class ModelCatalog extends ModelCatalog_base {
|
|
9
12
|
}
|
|
10
13
|
export {};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect } from "effect";
|
|
3
3
|
import type { ConversationId } from "../domain/message.entity.js";
|
|
4
|
+
import type { TokenUsage } from "../domain/token-usage.entity.js";
|
|
4
5
|
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
5
|
-
import type { SessionAddress } from "../session/sessions.entity.js";
|
|
6
|
+
import type { AdmittedTurn, SessionAddress } from "../session/sessions.entity.js";
|
|
6
7
|
import type { UserMessage } from "../turn/user-message.entity.js";
|
|
7
8
|
import type { MemoryReader } from "./memory.port.js";
|
|
8
9
|
import type { TurnEventsService, TurnTasksService } from "./turn-events.port.js";
|
|
@@ -12,6 +13,8 @@ declare const RunContext_base: Context.ServiceClass<RunContext, "efferent/RunCon
|
|
|
12
13
|
readonly session: SessionAddress;
|
|
13
14
|
readonly runId: string;
|
|
14
15
|
readonly userMessage: UserMessage;
|
|
16
|
+
/** The admitted turn as the session began it: its number, key, origin, command, claimed inbox items and the host's `meta`. */
|
|
17
|
+
readonly admitted: AdmittedTurn;
|
|
15
18
|
readonly memory: MemoryReader;
|
|
16
19
|
readonly events: TurnEventsService;
|
|
17
20
|
readonly tasks: TurnTasksService;
|
|
@@ -21,6 +24,8 @@ declare const RunContext_base: Context.ServiceClass<RunContext, "efferent/RunCon
|
|
|
21
24
|
readonly flush: Effect.Effect<void, HarnessError>;
|
|
22
25
|
/** Run a host store write in journal order (after everything queued before it). */
|
|
23
26
|
readonly write: <A, E>(op: Effect.Effect<A, E>) => Effect.Effect<A, E | HarnessError>;
|
|
27
|
+
/** The turn's usage so far: the usage of every `assistant.message` published in the turn, summed. */
|
|
28
|
+
readonly usage: Effect.Effect<TokenUsage>;
|
|
24
29
|
}>;
|
|
25
30
|
/** The current run, as tools, sections and run layers see it. Provided by the turn. */
|
|
26
31
|
export declare class RunContext extends RunContext_base {
|
|
@@ -18,7 +18,10 @@ declare const SessionLog_base: Context.ServiceClass<SessionLog, "efferent/Sessio
|
|
|
18
18
|
* session plus its head (see `session-log.entity.ts`). Everything above it
|
|
19
19
|
* (turns, leases, the inbox, memory) is the sessions plugin's; a backend
|
|
20
20
|
* only keeps the log, the head and the compare-and-swap, and passes
|
|
21
|
-
* `sessionLogConformance`.
|
|
21
|
+
* `sessionLogConformance`. One event can be large: a user's images are
|
|
22
|
+
* stored inline in its `turn.started`, up to `MEDIA_LIMITS.requestChars`
|
|
23
|
+
* base64 characters together, so a backend must hold an event of that size
|
|
24
|
+
* (the kit checks one).
|
|
22
25
|
*/
|
|
23
26
|
export declare class SessionLog extends SessionLog_base {
|
|
24
27
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect, Option, Scope, Stream } from "effect";
|
|
3
|
+
import type { AttachmentRejected } from "../domain/media.entity.js";
|
|
3
4
|
import type { ConversationId } from "../domain/message.entity.js";
|
|
4
5
|
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
5
6
|
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
|
+
import type { AdmittedTurn, BeginTurn, InboxFull, InboxItem, KeyConflict, NothingPending, NotResumable, ReservedKind, SessionAddress, SessionBusy, SessionPage, SessionView, TurnClosed, TurnDuplicate, TurnEnding, TurnRefused } from "../session/sessions.entity.js";
|
|
7
8
|
/** One event to record; the writer stamps the turn (or none, outside a turn). */
|
|
8
9
|
export interface TurnDraft {
|
|
9
10
|
readonly kind: string;
|
|
@@ -60,8 +61,9 @@ export interface TurnWriter {
|
|
|
60
61
|
* refused, and `flush` still waits for what is queued. Calls while it runs
|
|
61
62
|
* share its result. A stored end, or a turn closed elsewhere, is final;
|
|
62
63
|
* 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
|
|
64
|
-
* inbox items
|
|
64
|
+
* later end, the scope's own at the latest, tries again: the scope's with
|
|
65
|
+
* the last ending whose commit was tried. Returns how many inbox items
|
|
66
|
+
* wait.
|
|
65
67
|
*/
|
|
66
68
|
readonly end: (ending: TurnEnding) => Effect.Effect<{
|
|
67
69
|
readonly pending: number;
|
|
@@ -113,17 +115,44 @@ declare const Sessions_base: Context.ServiceClass<Sessions, "efferent/Sessions",
|
|
|
113
115
|
}, SessionMissing | SessionLogError>;
|
|
114
116
|
/**
|
|
115
117
|
* Open a turn, through the host's TurnAdmission. Its writer lives in the
|
|
116
|
-
* scope; a writer the scope closes unended ends
|
|
118
|
+
* scope; a writer the scope closes unended ends with the last ending it
|
|
119
|
+
* tried to store, or, when none was tried, as failed (`turn.unended`), or
|
|
120
|
+
* as interrupted (`turn.interrupted`) when the scope was interrupted.
|
|
121
|
+
* The input's `meta` is stored in `turn.started` and shown on the writer's
|
|
122
|
+
* `admitted`; it is not part of the key's fingerprint.
|
|
123
|
+
* A user's turn with `resumes: n` resumes turn `n`: it must be the
|
|
124
|
+
* session's last turn begun by a user (only inbox turns, and resumes of it
|
|
125
|
+
* that failed, were cancelled or were interrupted, may have run since) and
|
|
126
|
+
* have ended cancelled or interrupted (reaped included), or the begin
|
|
127
|
+
* fails with `NotResumable` and opens nothing. The check runs after the
|
|
128
|
+
* key's (a retried resume is `TurnDuplicate`) and after `SessionBusy`, in
|
|
129
|
+
* the opening commit; an `n` that is not a whole number of at least 1 is
|
|
130
|
+
* `NotResumable` (`missing`) before anything else, the admission included.
|
|
131
|
+
* `resumes` is stored in `turn.started`, shown on `admitted` and part of
|
|
132
|
+
* the key's fingerprint.
|
|
133
|
+
* A user message is normalised first (`normalizeUserMessage`), before
|
|
134
|
+
* anything else: an image its bytes do not support fails with
|
|
135
|
+
* `AttachmentRejected`, and the normalised message is what is stored,
|
|
136
|
+
* admitted and compared with an earlier turn of the same key.
|
|
117
137
|
*/
|
|
118
|
-
readonly begin: (address: SessionAddress, input: BeginTurn) => Effect.Effect<TurnWriter, SessionBusy | TurnDuplicate | KeyConflict | NothingPending | TurnRefused | SessionMissing | SessionLogError, Scope.Scope>;
|
|
138
|
+
readonly begin: (address: SessionAddress, input: BeginTurn) => Effect.Effect<TurnWriter, AttachmentRejected | SessionBusy | TurnDuplicate | KeyConflict | NothingPending | NotResumable | TurnRefused | SessionMissing | SessionLogError, Scope.Scope>;
|
|
119
139
|
/** Put an item in the inbox (once per id); `pending` counts what waits after it. */
|
|
120
140
|
readonly deliver: (address: SessionAddress, item: InboxItem) => Effect.Effect<{
|
|
121
141
|
readonly delivered: boolean;
|
|
122
142
|
readonly pending: number;
|
|
123
143
|
}, InboxFull | SessionMissing | SessionLogError>;
|
|
124
|
-
/**
|
|
144
|
+
/**
|
|
145
|
+
* Run inbox turns while items wait, the session is free and the host
|
|
146
|
+
* admits them, at most `maxTurns` (3), each begun with `meta`. A turn whose
|
|
147
|
+
* `run` succeeds ends completed; one whose `run` fails ends with its
|
|
148
|
+
* error's code (`turnEndingOf`, a `HarnessError` carried as a defect
|
|
149
|
+
* included): `turn.failed`, `turn.defect` or `turn.interrupted` when it has
|
|
150
|
+
* none. A `run` that interrupts itself counts an attempt for the items it
|
|
151
|
+
* took, even when it wrote nothing.
|
|
152
|
+
*/
|
|
125
153
|
readonly drain: <E, R>(address: SessionAddress, run: (writer: TurnWriter) => Effect.Effect<void, E, R>, options?: {
|
|
126
154
|
readonly maxTurns?: number;
|
|
155
|
+
readonly meta?: JsonObject;
|
|
127
156
|
}) => Effect.Effect<{
|
|
128
157
|
readonly turns: number;
|
|
129
158
|
}, SessionMissing | SessionLogError, R>;
|
|
@@ -28,19 +28,23 @@ export declare const SETTINGS_KEYS: readonly ["fallbackModel", "sandbox", "viMod
|
|
|
28
28
|
export type SettingsKey = (typeof SETTINGS_KEYS)[number];
|
|
29
29
|
declare const SettingsStore_base: Context.ServiceClass<SettingsStore, "@xandreed/core/SettingsStore", {
|
|
30
30
|
readonly load: Effect.Effect<EngineSettings, SettingsError>;
|
|
31
|
-
/** Persist one role's model selection (
|
|
32
|
-
*
|
|
31
|
+
/** Persist one role's model selection (a role choice); `None` clears
|
|
32
|
+
* the role so it falls back to its default again. A selection that is
|
|
33
|
+
* not `"<provider>:<modelId>"` fails with a `SettingsError` and writes
|
|
34
|
+
* nothing. */
|
|
33
35
|
readonly setRole: (role: ModelRole, selection: Option.Option<string>) => Effect.Effect<void, SettingsError>;
|
|
34
|
-
/** Persist one non-role key from its STRING form (
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* clears the key. */
|
|
36
|
+
/** Persist one non-role key from its STRING form (a settings edit): the
|
|
37
|
+
* adapter validates + coerces per key ("true", "3", "provider:model")
|
|
38
|
+
* and rejects a value that doesn't parse with a `SettingsError`,
|
|
39
|
+
* writing nothing; `None` clears the key. */
|
|
38
40
|
readonly set: (key: SettingsKey, value: Option.Option<string>) => Effect.Effect<void, SettingsError>;
|
|
39
41
|
}>;
|
|
40
42
|
/**
|
|
41
43
|
* Read-through settings port. `load` re-reads the backing store on every call
|
|
42
44
|
* so a value changed mid-session takes effect on the next turn — callers must
|
|
43
|
-
* not cache the result across turns.
|
|
45
|
+
* not cache the result across turns. A store may be read-only: then
|
|
46
|
+
* `setRole` and `set` fail with a `SettingsError` and write nothing.
|
|
47
|
+
* `settingsStoreConformance` checks a store against this contract.
|
|
44
48
|
*/
|
|
45
49
|
export declare class SettingsStore extends SettingsStore_base {
|
|
46
50
|
}
|
|
@@ -2,6 +2,7 @@ import { Context } from "effect";
|
|
|
2
2
|
import type { Effect, Option } from "effect";
|
|
3
3
|
import type { LanguageModel, Prompt, Tool } from "effect/ai";
|
|
4
4
|
import type { AgentMessage } from "../domain/message.entity.js";
|
|
5
|
+
import type { TokenUsage } from "../domain/token-usage.entity.js";
|
|
5
6
|
import type { HarnessError } from "../harness/plugin.entity.js";
|
|
6
7
|
import type { LogEntry } from "../memory/memory-log.entity.js";
|
|
7
8
|
import type { CompletionVerdict } from "../turn/turn-event.entity.js";
|
|
@@ -44,12 +45,31 @@ export interface StepRequest {
|
|
|
44
45
|
readonly dispatch: (step: number, request: ModelDispatch) => Effect.Effect<void, HarnessError>;
|
|
45
46
|
/** Persist a step's appended messages; returns their log entries. */
|
|
46
47
|
readonly record: (step: number, tail: ReadonlyArray<AgentMessage>) => Effect.Effect<ReadonlyArray<LogEntry>, HarnessError>;
|
|
48
|
+
/**
|
|
49
|
+
* A provider refused the step's request over an image (an `InvalidRequestError`
|
|
50
|
+
* that names one; `reason` is what it said). Records an `OmitMedia`
|
|
51
|
+
* compaction of the entries whose images that request sent and answers
|
|
52
|
+
* true, so the loop plans the step again and sends it once more, the
|
|
53
|
+
* images as label lines; false when the request sent no image, and the
|
|
54
|
+
* step fails. The step's next `plan`, that one only, keeps the model
|
|
55
|
+
* choice, system prompt and directive the refused request was planned
|
|
56
|
+
* with; any other `plan` of a step asks the policy again.
|
|
57
|
+
*/
|
|
58
|
+
readonly onMediaRejected: (reason: string) => Effect.Effect<boolean, HarnessError>;
|
|
47
59
|
readonly completion: (step: StepInfo) => Effect.Effect<CompletionVerdict, HarnessError>;
|
|
48
60
|
readonly steering: Effect.Effect<Option.Option<string>, HarnessError>;
|
|
49
61
|
readonly correctives: Option.Option<Correctives>;
|
|
50
62
|
readonly events: TurnEventsService;
|
|
51
63
|
readonly tasks: TurnTasksService;
|
|
52
64
|
readonly cacheKey: Option.Option<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Whether the run's spans may carry prompt and response content: the loop
|
|
67
|
+
* must provide it as `CurrentTraceContent` to the model calls it makes,
|
|
68
|
+
* whatever the caller's (`stepLoopConformance` checks it), so they read it
|
|
69
|
+
* too. The policy's `captureTraceContent`, else the agent's, else
|
|
70
|
+
* `CurrentTraceContent` where the run starts (off by default).
|
|
71
|
+
*/
|
|
72
|
+
readonly captureTraceContent: boolean;
|
|
53
73
|
}
|
|
54
74
|
export interface ModelDispatch {
|
|
55
75
|
readonly prompt: Prompt.Prompt;
|
|
@@ -62,6 +82,8 @@ export interface RunResult {
|
|
|
62
82
|
readonly reason: "completed" | "step-cap" | "degenerate-loop";
|
|
63
83
|
readonly text: string;
|
|
64
84
|
readonly steps: number;
|
|
85
|
+
/** The run's provider calls summed: exactly the usage its `assistant.message` events carried. */
|
|
86
|
+
readonly usage: TokenUsage;
|
|
65
87
|
}
|
|
66
88
|
declare const StepLoop_base: Context.ServiceClass<StepLoop, "efferent/StepLoop", {
|
|
67
89
|
readonly id: string;
|
|
@@ -75,10 +97,16 @@ declare const StepLoop_base: Context.ServiceClass<StepLoop, "efferent/StepLoop",
|
|
|
75
97
|
* (after the tail is recorded) < `completion.evaluated`; a planned batch
|
|
76
98
|
* makes no provider call; a forced tool choice is honoured; a verdict
|
|
77
99
|
* awaiting tasks joins them and is evaluated once more; no provider call
|
|
78
|
-
* follows a complete verdict.
|
|
100
|
+
* follows a complete verdict; `RunResult.usage` is the sum of the usage
|
|
101
|
+
* the run's `assistant.message` events carried; the model calls read the
|
|
102
|
+
* request's `captureTraceContent` as `CurrentTraceContent`. A loop that streams and
|
|
103
|
+
* falls back to a non-streamed call publishes `stream.fallback`; the kit
|
|
104
|
+
* does not stream, so it does not check that.
|
|
79
105
|
* Every real provider attempt runs `request.dispatch` immediately before
|
|
80
106
|
* invoking the model; a failed durable check prevents the call. Planned
|
|
81
|
-
* batches skip that hook because they make no provider request.
|
|
107
|
+
* batches skip that hook because they make no provider request. A request
|
|
108
|
+
* a provider refuses over an image is sent once more after
|
|
109
|
+
* `request.onMediaRejected` answers true, planned again first.
|
|
82
110
|
*/
|
|
83
111
|
export declare class StepLoop extends StepLoop_base {
|
|
84
112
|
}
|
|
@@ -43,7 +43,11 @@ declare const TaskRunner_base: Context.ServiceClass<TaskRunner, "efferent/TaskRu
|
|
|
43
43
|
* Where background work runs: a fiber of this process, or the host's own
|
|
44
44
|
* mechanism (e.g. a serverless waitUntil). `run` returns once the work is
|
|
45
45
|
* handed over; the work is told when it must be done by (Clock time), if
|
|
46
|
-
* the runner has a limit, so a task ends interrupted rather than lost.
|
|
46
|
+
* the runner has a limit, so a task ends interrupted rather than lost. The
|
|
47
|
+
* work goes on after its caller (the turn that started a task) ends, and
|
|
48
|
+
* runs without the caller's services; on fibers of this process, it is
|
|
49
|
+
* interrupted when the runner's scope closes. `taskRunnerConformance`
|
|
50
|
+
* checks a runner.
|
|
47
51
|
*/
|
|
48
52
|
export declare class TaskRunner extends TaskRunner_base {
|
|
49
53
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
2
|
import type { Effect } from "effect";
|
|
3
|
+
import type { JsonObject } from "../session/session-log.entity.js";
|
|
3
4
|
import type { SessionAddress, TurnRefused } from "../session/sessions.entity.js";
|
|
4
5
|
/** The turn a host is asked to admit. */
|
|
5
6
|
export interface TurnToAdmit {
|
|
@@ -7,6 +8,10 @@ export interface TurnToAdmit {
|
|
|
7
8
|
readonly origin: "user" | "inbox";
|
|
8
9
|
readonly runId: string;
|
|
9
10
|
readonly key: string;
|
|
11
|
+
/** The host's metadata the turn is begun with (`{}` when none was given): a tenant or a quota key to count by. */
|
|
12
|
+
readonly meta: JsonObject;
|
|
13
|
+
/** The earlier turn a user's turn resumes (a whole number of at least 1), only when it resumes one. */
|
|
14
|
+
readonly resumes?: number;
|
|
10
15
|
}
|
|
11
16
|
declare const TurnAdmission_base: Context.ServiceClass<TurnAdmission, "efferent/TurnAdmission", {
|
|
12
17
|
readonly admit: <A, E>(turn: TurnToAdmit, open: Effect.Effect<A, E>) => Effect.Effect<A, E | TurnRefused>;
|
|
@@ -15,8 +20,9 @@ declare const TurnAdmission_base: Context.ServiceClass<TurnAdmission, "efferent/
|
|
|
15
20
|
* The host's say on every turn before it opens: a user's, the inbox's, a
|
|
16
21
|
* background task's. `admit` runs around the one commit that opens the turn,
|
|
17
22
|
* never around the turn's later writes, so a host can count and open in one
|
|
18
|
-
* transaction; a duplicate
|
|
19
|
-
*
|
|
23
|
+
* transaction; a duplicate, a key conflict, a busy session or a turn that
|
|
24
|
+
* cannot be resumed (`NotResumable`) fails inside it and counts nothing. A
|
|
25
|
+
* refusal opens nothing.
|
|
20
26
|
*/
|
|
21
27
|
export declare class TurnAdmission extends TurnAdmission_base {
|
|
22
28
|
}
|
|
@@ -24,7 +24,14 @@ export interface SubscribeOptions {
|
|
|
24
24
|
*/
|
|
25
25
|
export interface TurnEventsService {
|
|
26
26
|
readonly publish: (event: TurnEvent) => Effect.Effect<void, HarnessError>;
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Active until the caller's scope closes. `select` narrows and decodes.
|
|
29
|
+
* The handler runs with the services where it subscribed, without their
|
|
30
|
+
* trace state (`replayableContext`): an inline handler's spans nest under
|
|
31
|
+
* the publisher's span, a background handler's under where it subscribed
|
|
32
|
+
* (its fiber starts there), and both read the publisher's
|
|
33
|
+
* `CurrentTraceContent`.
|
|
34
|
+
*/
|
|
28
35
|
readonly subscribe: <E, R>(select: (event: TurnEvent) => Option.Option<E>, handle: (event: E) => Effect.Effect<void, HarnessError, R>, options?: SubscribeOptions) => Effect.Effect<void, never, R | Scope.Scope>;
|
|
29
36
|
/** Wait until every background subscription has handled what was published to it. */
|
|
30
37
|
readonly drain: Effect.Effect<void, HarnessError>;
|
|
@@ -91,11 +91,29 @@ export interface TurnLiveInput {
|
|
|
91
91
|
/** The agent-level defaults of one run; a policy overrides limits and budget. */
|
|
92
92
|
export interface TurnRunOptions {
|
|
93
93
|
readonly limits?: Partial<LoopLimits>;
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* The run's token budget when the policy gives none; 64 000 by default. An
|
|
96
|
+
* integer of at least 1 (else the run fails with `turn.budget`): the target
|
|
97
|
+
* memory compaction keeps each request under (system prompt, tool schemas
|
|
98
|
+
* and messages, estimated), not a provider limit. The memory strategy is
|
|
99
|
+
* given the whole budget at the turn's start, and at each step what the
|
|
100
|
+
* system prompt and the active tools' schemas leave of it
|
|
101
|
+
* (`context.budget` when they leave nothing): the window strategy
|
|
102
|
+
* compacts, spills and drops older turns to fit the budget it is given
|
|
103
|
+
* (and fails with `context.budget` when the current turn alone does not),
|
|
104
|
+
* the summary strategy summarizes past its `triggerRatio` of it, and the
|
|
105
|
+
* digester ignores it. Each step's `context.built` records it.
|
|
106
|
+
*/
|
|
95
107
|
readonly budgetTokens?: number;
|
|
96
108
|
/** The provider prompt-cache key (see `cacheKeyOf`); none by default. */
|
|
97
109
|
readonly cacheKey?: Option.Option<string>;
|
|
98
110
|
/** A mid-run user message, consulted between steps. */
|
|
99
111
|
readonly steering?: Effect.Effect<Option.Option<string>, HarnessError>;
|
|
112
|
+
/**
|
|
113
|
+
* Whether the run's spans may carry prompt and response content
|
|
114
|
+
* (`StepRequest.captureTraceContent`) when the policy does not say; when
|
|
115
|
+
* neither does, `CurrentTraceContent` where the run starts (off by default).
|
|
116
|
+
*/
|
|
117
|
+
readonly captureTraceContent?: boolean;
|
|
100
118
|
}
|
|
101
119
|
export {};
|