@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.
Files changed (148) hide show
  1. package/README.md +1 -1
  2. package/dist/conformance.functions.d.ts +34 -0
  3. package/dist/conformance.functions.js +25 -0
  4. package/dist/domain/bash.entity.d.ts +82 -0
  5. package/dist/domain/bash.entity.functions.d.ts +17 -0
  6. package/dist/domain/bash.entity.functions.js +26 -0
  7. package/dist/domain/bash.entity.functions.test.d.ts +1 -0
  8. package/dist/domain/bash.entity.js +30 -0
  9. package/dist/domain/file-system.entity.d.ts +91 -0
  10. package/dist/domain/file-system.entity.functions.d.ts +18 -0
  11. package/dist/domain/file-system.entity.functions.js +30 -0
  12. package/dist/domain/file-system.entity.js +37 -0
  13. package/dist/domain/loop-event.entity.d.ts +9 -0
  14. package/dist/domain/media.entity.d.ts +79 -0
  15. package/dist/domain/media.entity.functions.d.ts +76 -0
  16. package/dist/domain/media.entity.functions.js +110 -0
  17. package/dist/domain/media.entity.js +38 -0
  18. package/dist/domain/media.entity.test.d.ts +1 -0
  19. package/dist/domain/message.entity.d.ts +157 -5
  20. package/dist/domain/message.entity.js +8 -4
  21. package/dist/domain/model-catalog.entity.d.ts +2 -0
  22. package/dist/domain/model-catalog.entity.js +2 -1
  23. package/dist/domain/token-usage.entity.d.ts +45 -1
  24. package/dist/domain/token-usage.entity.functions.d.ts +30 -1
  25. package/dist/domain/token-usage.entity.functions.js +24 -4
  26. package/dist/domain/token-usage.entity.js +19 -2
  27. package/dist/domain/token-usage.entity.test.d.ts +1 -0
  28. package/dist/harness/capability.entity.functions.js +2 -1
  29. package/dist/harness/plugin.adapter.d.ts +3 -0
  30. package/dist/harness/plugin.adapter.js +7 -1
  31. package/dist/harness/skill-files.entity.d.ts +101 -0
  32. package/dist/harness/skill-files.entity.functions.d.ts +58 -0
  33. package/dist/harness/skill-files.entity.functions.js +150 -0
  34. package/dist/harness/skill-files.entity.functions.test.d.ts +1 -0
  35. package/dist/harness/skill-files.entity.js +25 -0
  36. package/dist/index.d.ts +48 -8
  37. package/dist/index.js +67 -6
  38. package/dist/loop/mapping.d.ts +12 -6
  39. package/dist/loop/mapping.js +30 -6
  40. package/dist/loop/stepContext.d.ts +8 -0
  41. package/dist/loop/stepContext.js +1 -1
  42. package/dist/loop/traceContent.d.ts +29 -0
  43. package/dist/loop/traceContent.js +4 -0
  44. package/dist/loop/traceContent.test.d.ts +1 -0
  45. package/dist/memory/memory-log.entity.d.ts +152 -14
  46. package/dist/memory/memory-log.entity.functions.d.ts +35 -5
  47. package/dist/memory/memory-log.entity.functions.js +59 -20
  48. package/dist/memory/memory-log.entity.js +19 -6
  49. package/dist/memory/memory-session.js +10 -6
  50. package/dist/memory/memory.conformance.d.ts +8 -1
  51. package/dist/memory/memory.conformance.js +32 -0
  52. package/dist/models/auth-store.conformance.d.ts +13 -0
  53. package/dist/models/auth-store.conformance.js +73 -0
  54. package/dist/models/auth-store.conformance.test.d.ts +1 -0
  55. package/dist/models/model-catalog.conformance.d.ts +15 -0
  56. package/dist/models/model-catalog.conformance.js +27 -0
  57. package/dist/models/model-catalog.conformance.test.d.ts +1 -0
  58. package/dist/models/settings-store.conformance.d.ts +26 -0
  59. package/dist/models/settings-store.conformance.js +80 -0
  60. package/dist/models/settings-store.conformance.test.d.ts +1 -0
  61. package/dist/ports/activity.port.d.ts +35 -0
  62. package/dist/ports/activity.port.js +7 -0
  63. package/dist/ports/auth-store.port.d.ts +7 -5
  64. package/dist/ports/bash.port.d.ts +22 -0
  65. package/dist/ports/bash.port.js +4 -0
  66. package/dist/ports/capability.port.d.ts +11 -1
  67. package/dist/ports/file-system.port.d.ts +44 -15
  68. package/dist/ports/file-system.port.js +1 -7
  69. package/dist/ports/memory.port.d.ts +13 -1
  70. package/dist/ports/model-catalog.port.d.ts +4 -1
  71. package/dist/ports/run-context.port.d.ts +6 -1
  72. package/dist/ports/session-log.port.d.ts +4 -1
  73. package/dist/ports/sessions.port.d.ts +35 -6
  74. package/dist/ports/settings-store.port.d.ts +11 -7
  75. package/dist/ports/step-loop.port.d.ts +30 -2
  76. package/dist/ports/tasks.port.d.ts +5 -1
  77. package/dist/ports/turn-admission.port.d.ts +8 -2
  78. package/dist/ports/turn-events.port.d.ts +8 -1
  79. package/dist/ports/turn-scope.port.d.ts +19 -1
  80. package/dist/ports/turn.port.d.ts +70 -5
  81. package/dist/ports/utility-llm.port.d.ts +2 -0
  82. package/dist/session/activity.entity.d.ts +42 -0
  83. package/dist/session/activity.entity.functions.d.ts +21 -0
  84. package/dist/session/activity.entity.functions.js +23 -0
  85. package/dist/session/activity.entity.functions.test.d.ts +1 -0
  86. package/dist/session/activity.entity.js +15 -0
  87. package/dist/session/chassis.js +2 -1
  88. package/dist/session/session-event.entity.d.ts +68 -6
  89. package/dist/session/session-event.entity.functions.d.ts +34 -2
  90. package/dist/session/session-event.entity.functions.js +54 -16
  91. package/dist/session/session-event.entity.js +19 -2
  92. package/dist/session/session-log.conformance.d.ts +4 -3
  93. package/dist/session/session-log.conformance.js +16 -14
  94. package/dist/session/session-log.recovery.conformance.d.ts +40 -0
  95. package/dist/session/session-log.recovery.conformance.js +143 -0
  96. package/dist/session/session-log.recovery.conformance.test.d.ts +1 -0
  97. package/dist/session/sessions.conformance.d.ts +79 -0
  98. package/dist/session/sessions.conformance.js +355 -0
  99. package/dist/session/sessions.entity.d.ts +36 -3
  100. package/dist/session/sessions.entity.functions.d.ts +42 -0
  101. package/dist/session/sessions.entity.functions.js +26 -0
  102. package/dist/session/sessions.entity.js +17 -4
  103. package/dist/session/sessions.entity.test.d.ts +1 -0
  104. package/dist/session/tasks.conformance.d.ts +70 -0
  105. package/dist/session/tasks.conformance.js +213 -0
  106. package/dist/session/tasks.conformance.test.d.ts +1 -0
  107. package/dist/turn/model-request.entity.d.ts +4 -0
  108. package/dist/turn/model-request.entity.js +7 -2
  109. package/dist/turn/step-loop.conformance.d.ts +4 -1
  110. package/dist/turn/step-loop.conformance.js +73 -7
  111. package/dist/turn/tool-registry.conformance.d.ts +38 -0
  112. package/dist/turn/tool-registry.conformance.js +206 -0
  113. package/dist/turn/turn-bus.js +4 -3
  114. package/dist/turn/turn-event.entity.d.ts +134 -34
  115. package/dist/turn/turn-event.entity.functions.d.ts +11 -0
  116. package/dist/turn/turn-event.entity.functions.js +9 -1
  117. package/dist/turn/turn-event.entity.js +76 -3
  118. package/dist/turn/turn-event.entity.test.d.ts +1 -0
  119. package/dist/turn/turn-lifecycle.d.ts +46 -8
  120. package/dist/turn/turn-lifecycle.js +33 -3
  121. package/dist/turn/turn-lifecycle.test.d.ts +1 -0
  122. package/dist/turn/turn-run.d.ts +15 -3
  123. package/dist/turn/turn-run.js +37 -9
  124. package/dist/turn/turn.adapter.d.ts +6 -5
  125. package/dist/turn/turn.adapter.js +15 -3
  126. package/dist/turn/turn.conformance.d.ts +11 -2
  127. package/dist/turn/turn.conformance.js +63 -2
  128. package/dist/turn/user-message.entity.d.ts +14 -4
  129. package/dist/turn/user-message.entity.functions.d.ts +21 -0
  130. package/dist/turn/user-message.entity.functions.js +24 -0
  131. package/dist/turn/user-message.entity.js +6 -8
  132. package/dist/turn/user-message.entity.test.d.ts +1 -0
  133. package/dist/util/glob.d.ts +30 -0
  134. package/dist/util/glob.js +91 -0
  135. package/dist/util/glob.test.d.ts +1 -0
  136. package/dist/workspace/bash.conformance.d.ts +37 -0
  137. package/dist/workspace/bash.conformance.js +120 -0
  138. package/dist/workspace/bash.conformance.test.d.ts +1 -0
  139. package/dist/workspace/file-system.conformance.d.ts +38 -0
  140. package/dist/workspace/file-system.conformance.js +254 -0
  141. package/dist/workspace/file-system.conformance.test.d.ts +1 -0
  142. package/dist/workspace/file-system.memory.adapter.d.ts +23 -0
  143. package/dist/workspace/file-system.memory.adapter.js +132 -0
  144. package/package.json +1 -1
  145. package/dist/harness/skill-files.d.ts +0 -17
  146. package/dist/harness/skill-files.js +0 -25
  147. package/dist/ports/shell.port.d.ts +0 -32
  148. package/dist/ports/shell.port.js +0 -16
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # @xandreed/core
2
2
 
3
- Efferent composable agent framework, 0.13.0. Node 24 or Bun.
3
+ Efferent composable agent framework, 0.14.0. Node 24 or Bun.
4
4
 
5
5
  Documentation: https://github.com/xandreeddev/efferent
@@ -0,0 +1,34 @@
1
+ import { Effect, Option } from "effect";
2
+ import type { Fiber } from "effect";
3
+ import { ConformanceFailure } from "./conformance.entity.js";
4
+ import type { ConformanceCheck } from "./conformance.entity.js";
5
+ import { ConversationId } from "./domain/message.entity.js";
6
+ import type { TokenUsage } from "./domain/token-usage.entity.js";
7
+ import type { SessionHeader, SessionLogEvent } from "./session/session-log.entity.js";
8
+ export declare const fail: (check: string, message: string) => Effect.Effect<never, ConformanceFailure, never>;
9
+ export declare const expect: (check: string, holds: boolean, message: string) => Effect.Effect<void, ConformanceFailure>;
10
+ /** Two usages with every count equal. */
11
+ export declare const sameUsage: (a: TokenUsage, b: TokenUsage) => boolean;
12
+ /** A 1x1 PNG, as base64: the image the kits attach. */
13
+ export declare const pixelPng = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
14
+ /** Each event as `kind@turn` (`kind` alone outside a turn), joined. */
15
+ export declare const kindsOf: (events: ReadonlyArray<SessionLogEvent>) => string;
16
+ /** Whether `fiber` completes within a few turns of the scheduler (an `idle` that should be settled). */
17
+ export declare const settles: (fiber: Fiber.Fiber<unknown, unknown>, tries?: number) => Effect.Effect<boolean>;
18
+ /** Read `value` until `holds`, letting other fibers run in between; the last value read. */
19
+ export declare const eventually: <A>(value: Effect.Effect<A>, holds: (a: A) => boolean, tries?: number) => Effect.Effect<A>;
20
+ /** A fresh id per session, so a kit can run against a shared store. */
21
+ export declare const freshId: Effect.Effect<string & import("effect/Brand").Brand<"ConversationId">, never, never>;
22
+ export declare const headerOf: (id: ConversationId, owner: string, parent?: Option.Option<{
23
+ readonly id: ConversationId;
24
+ readonly through: number;
25
+ readonly turnAtFork: number;
26
+ }>) => SessionHeader;
27
+ /**
28
+ * One check run under a fresh owner. A failure the body did not raise as a
29
+ * `ConformanceFailure` (a port's own error, a defect-free typed failure) is
30
+ * reported under `id` as unexpected, with its tag.
31
+ */
32
+ export declare const check: (name: string, id: string, body: (owner: string) => Effect.Effect<void, unknown>) => ConformanceCheck;
33
+ /** Run `effect` with the wall clock stopped at `at`. */
34
+ export declare const atTime: (at: number) => <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
@@ -0,0 +1,25 @@
1
+ import { Clock, Effect, Option } from "effect";
2
+ import { ConformanceFailure } from "./conformance.entity.js";
3
+ import { ConversationId } from "./domain/message.entity.js";
4
+ import { zeroUsage } from "./domain/token-usage.entity.functions.js";
5
+ export const fail = (check, message) => Effect.fail(new ConformanceFailure({ check, message })), expect = (check, holds, message) => holds ? Effect.void : fail(check, message), sameUsage = (a, b) => Object.keys(zeroUsage).every((key) => a[key] === b[key]), pixelPng = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==", kindsOf = (events) => events.map((event) => `${event.kind}${Option.match(event.turn, { onNone: () => "", onSome: (turn) => `@${turn}` })}`).join(), settles = (fiber, tries = 50) => fiber.pollUnsafe() !== void 0 ? Effect.succeed(!0) : tries <= 0 ? Effect.succeed(!1) : Effect.yieldNow.pipe(Effect.andThen(Effect.suspend(() => settles(fiber, tries - 1)))), eventually = (value, holds, tries = 200) => value.pipe(Effect.flatMap((now) => holds(now) || tries <= 0 ? Effect.succeed(now) : Effect.yieldNow.pipe(Effect.andThen(Effect.suspend(() => eventually(value, holds, tries - 1)))))), freshId = Effect.sync(() => ConversationId.make(crypto.randomUUID())), headerOf = (id, owner, parent = Option.none()) => ({
6
+ id,
7
+ owner,
8
+ origin: "user",
9
+ createdAt: 1767225600000,
10
+ meta: { title: "conformance", nested: { list: [1, "two", null] } },
11
+ parent
12
+ }), check = (name, id, body) => ({
13
+ name,
14
+ run: freshId.pipe(Effect.flatMap((owner) => body(`owner-${owner}`)), Effect.catch((error) => error instanceof ConformanceFailure ? Effect.fail(error) : fail(id, `unexpected ${typeof error === "object" && error !== null && "_tag" in error ? String(error._tag) : "error"}: ${JSON.stringify(error)}`)))
15
+ });
16
+ const stoppedAt = (at, clock) => ({
17
+ currentTimeMillisUnsafe: () => at,
18
+ currentTimeMillis: Effect.succeed(at),
19
+ currentTimeNanosUnsafe: () => BigInt(at) * 1000000n,
20
+ currentTimeNanos: Effect.succeed(BigInt(at) * 1000000n),
21
+ monotonicTimeNanosUnsafe: () => clock.monotonicTimeNanosUnsafe(),
22
+ monotonicTimeNanos: Effect.sync(() => clock.monotonicTimeNanosUnsafe()),
23
+ sleep: (duration) => clock.sleep(duration)
24
+ });
25
+ export const atTime = (at) => (effect) => Clock.clockWith((clock) => Effect.provideService(effect, Clock.Clock, stoppedAt(at, clock)));
@@ -0,0 +1,82 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * The parent environment a command inherits by default: these names, and
4
+ * every name a trailing `*` prefixes. Provider keys and other host secrets
5
+ * stay out unless a host passes them in `env` or widens `inheritEnv`.
6
+ */
7
+ export declare const BASH_ENV_ALLOWLIST: ReadonlyArray<string>;
8
+ /**
9
+ * How a command runs. `cwd` is an absolute directory that must exist.
10
+ * `env` is set over what is inherited; `inheritEnv` says what is inherited
11
+ * from the parent environment: `true` everything, `false` nothing, or an
12
+ * allowlist of names where a trailing `*` matches a prefix (default
13
+ * `BASH_ENV_ALLOWLIST`). `stdin` (text, written as UTF-8, or bytes) is
14
+ * written to the command's standard input, which is then closed (without it, the command reads end-of-file at
15
+ * once). After `timeoutMs` the command's whole process group is killed.
16
+ */
17
+ export declare const BashOptions: Schema.Struct<{
18
+ readonly cwd: Schema.String;
19
+ readonly env: Schema.optionalKey<Schema.$Record<Schema.String, Schema.String>>;
20
+ readonly inheritEnv: Schema.optionalKey<Schema.Union<readonly [Schema.Boolean, Schema.$Array<Schema.String>]>>;
21
+ readonly stdin: Schema.optionalKey<Schema.Union<readonly [Schema.String, Schema.Uint8Array]>>;
22
+ readonly timeoutMs: Schema.optionalKey<Schema.Int>;
23
+ }>;
24
+ export type BashOptions = typeof BashOptions.Type;
25
+ /**
26
+ * How a command ended: it exited (`exit`), a signal killed it (`signal`),
27
+ * it ran past `timeoutMs` and was killed (`timeout`), or its caller stopped
28
+ * the stream before it ended and it was killed (`interrupted`, which only
29
+ * `collectBashResult` can see).
30
+ */
31
+ export declare const BashTermination: Schema.Literals<readonly ["exit", "signal", "timeout", "interrupted"]>;
32
+ export type BashTermination = typeof BashTermination.Type;
33
+ /**
34
+ * Why a command could not run: the shell could not be spawned
35
+ * (`SpawnFailed`), `cwd` does not exist or is not a directory
36
+ * (`CwdMissing`), or the shell is not installed (`ShellMissing`). A command
37
+ * that runs and fails is a result, never a `BashError`.
38
+ */
39
+ export declare const BashErrorReason: Schema.Literals<readonly ["SpawnFailed", "CwdMissing", "ShellMissing"]>;
40
+ export type BashErrorReason = typeof BashErrorReason.Type;
41
+ declare const BashError_base: Schema.Class<BashError, Schema.TaggedStruct<"BashError", {
42
+ readonly reason: Schema.Literals<readonly ["SpawnFailed", "CwdMissing", "ShellMissing"]>;
43
+ readonly message: Schema.String;
44
+ }>, import("effect/Cause").YieldableError>;
45
+ export declare class BashError extends BashError_base {
46
+ }
47
+ /** Output as it arrives, decoded as UTF-8 per stream (a character split between reads arrives whole). */
48
+ export declare const BashChunk: Schema.TaggedStruct<"BashChunk", {
49
+ readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
50
+ readonly text: Schema.String;
51
+ }>;
52
+ export type BashChunk = typeof BashChunk.Type;
53
+ /** The end of a command: its exit code when it exited, the signal when one killed it, how long it ran. */
54
+ export declare const BashExit: Schema.TaggedStruct<"BashExit", {
55
+ readonly termination: Schema.Literals<readonly ["exit", "signal", "timeout", "interrupted"]>;
56
+ readonly exitCode: Schema.OptionFromNullOr<Schema.Int>;
57
+ readonly signal: Schema.OptionFromNullOr<Schema.String>;
58
+ readonly durationMs: Schema.Number;
59
+ }>;
60
+ export type BashExit = typeof BashExit.Type;
61
+ /** What `Bash.stream` emits: chunks as they come, then exactly one `BashExit`, last. */
62
+ export declare const BashEvent: Schema.Union<readonly [Schema.TaggedStruct<"BashChunk", {
63
+ readonly stream: Schema.Literals<readonly ["stdout", "stderr"]>;
64
+ readonly text: Schema.String;
65
+ }>, Schema.TaggedStruct<"BashExit", {
66
+ readonly termination: Schema.Literals<readonly ["exit", "signal", "timeout", "interrupted"]>;
67
+ readonly exitCode: Schema.OptionFromNullOr<Schema.Int>;
68
+ readonly signal: Schema.OptionFromNullOr<Schema.String>;
69
+ readonly durationMs: Schema.Number;
70
+ }>]>;
71
+ export type BashEvent = typeof BashEvent.Type;
72
+ /** A whole command's output and end (`Bash.exec`). A non-zero exit is a result like any other. */
73
+ export declare const BashResult: Schema.Struct<{
74
+ readonly stdout: Schema.String;
75
+ readonly stderr: Schema.String;
76
+ readonly exitCode: Schema.OptionFromNullOr<Schema.Int>;
77
+ readonly signal: Schema.OptionFromNullOr<Schema.String>;
78
+ readonly termination: Schema.Literals<readonly ["exit", "signal", "timeout", "interrupted"]>;
79
+ readonly durationMs: Schema.Number;
80
+ }>;
81
+ export type BashResult = typeof BashResult.Type;
82
+ export {};
@@ -0,0 +1,17 @@
1
+ import { Effect, Stream } from "effect";
2
+ import type { BashError, BashEvent, BashOptions, BashResult } from "./bash.entity.js";
3
+ /**
4
+ * The environment a command gets: the parent's variables `inheritEnv`
5
+ * admits (all, none, or an allowlist where a trailing `*` matches a prefix;
6
+ * `BASH_ENV_ALLOWLIST` by default), then `env` over them. Unset parent
7
+ * variables are skipped. Every `Bash` adapter builds the environment with
8
+ * this, so the allowlist means the same everywhere.
9
+ */
10
+ export declare const resolveBashEnv: (parent: Readonly<Record<string, string | undefined>>, options: Pick<BashOptions, "env" | "inheritEnv">) => Readonly<Record<string, string>>;
11
+ /**
12
+ * A command's events folded into its result: `Bash.exec` is this over
13
+ * `Bash.stream`. A stream that ends without its `BashExit` (its consumer
14
+ * cut it short, e.g. with `Stream.interruptWhen`, and the adapter killed
15
+ * the command) gives `termination: "interrupted"` with the output so far.
16
+ */
17
+ export declare const collectBashResult: <R>(events: Stream.Stream<BashEvent, BashError, R>) => Effect.Effect<BashResult, BashError, R>;
@@ -0,0 +1,26 @@
1
+ import { Clock, Effect, Option, Stream } from "effect";
2
+ import { BASH_ENV_ALLOWLIST } from "./bash.entity.js";
3
+ export const resolveBashEnv = (parent, options) => {
4
+ const inherit = options.inheritEnv ?? BASH_ENV_ALLOWLIST, admitted = (name) => typeof inherit === "boolean" ? inherit : inherit.some((entry) => entry.endsWith("*") ? name.startsWith(entry.slice(0, -1)) : name === entry), inherited = Object.entries(parent).flatMap(([name, value]) => value !== void 0 && admitted(name) ? [[name, value]] : []);
5
+ return { ...Object.fromEntries(inherited), ...options.env };
6
+ }, collectBashResult = (events) => Effect.gen(function* () {
7
+ const started = yield* Clock.currentTimeMillis, collected = yield* Stream.runFold(events, () => ({ stdout: "", stderr: "", exit: Option.none() }), (state, event) => event._tag === "BashExit" ? { ...state, exit: Option.some(event) } : event.stream === "stdout" ? { ...state, stdout: state.stdout + event.text } : { ...state, stderr: state.stderr + event.text }), ended = yield* Clock.currentTimeMillis;
8
+ return Option.match(collected.exit, {
9
+ onNone: () => ({
10
+ stdout: collected.stdout,
11
+ stderr: collected.stderr,
12
+ exitCode: Option.none(),
13
+ signal: Option.none(),
14
+ termination: "interrupted",
15
+ durationMs: ended - started
16
+ }),
17
+ onSome: (exit) => ({
18
+ stdout: collected.stdout,
19
+ stderr: collected.stderr,
20
+ exitCode: exit.exitCode,
21
+ signal: exit.signal,
22
+ termination: exit.termination,
23
+ durationMs: exit.durationMs
24
+ })
25
+ });
26
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { Schema } from "effect";
2
+ export const BASH_ENV_ALLOWLIST = ["PATH", "HOME", "USER", "LOGNAME", "LANG", "LC_*", "TERM", "SHELL", "TMPDIR", "TZ"], BashOptions = Schema.Struct({
3
+ cwd: Schema.String,
4
+ env: Schema.optionalKey(Schema.Record(Schema.String, Schema.String)),
5
+ inheritEnv: Schema.optionalKey(Schema.Union([Schema.Boolean, Schema.Array(Schema.String)])),
6
+ stdin: Schema.optionalKey(Schema.Union([Schema.String, Schema.Uint8Array])),
7
+ timeoutMs: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1)))
8
+ }), BashTermination = Schema.Literals(["exit", "signal", "timeout", "interrupted"]), BashErrorReason = Schema.Literals(["SpawnFailed", "CwdMissing", "ShellMissing"]);
9
+
10
+ export class BashError extends Schema.TaggedError()("BashError", {
11
+ reason: BashErrorReason,
12
+ message: Schema.String
13
+ }) {
14
+ }
15
+ export const BashChunk = Schema.TaggedStruct("BashChunk", {
16
+ stream: Schema.Literals(["stdout", "stderr"]),
17
+ text: Schema.String
18
+ }), BashExit = Schema.TaggedStruct("BashExit", {
19
+ termination: BashTermination,
20
+ exitCode: Schema.OptionFromNullOr(Schema.Int),
21
+ signal: Schema.OptionFromNullOr(Schema.String),
22
+ durationMs: Schema.Number
23
+ }), BashEvent = Schema.Union([BashChunk, BashExit]), BashResult = Schema.Struct({
24
+ stdout: Schema.String,
25
+ stderr: Schema.String,
26
+ exitCode: Schema.OptionFromNullOr(Schema.Int),
27
+ signal: Schema.OptionFromNullOr(Schema.String),
28
+ termination: BashTermination,
29
+ durationMs: Schema.Number
30
+ });
@@ -0,0 +1,91 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * Why a file-system call failed, the same on every backend:
4
+ * - `NotFound`: the path, or a directory on the way to it, does not exist;
5
+ * - `Exists`: something is already there (a non-recursive `mkdir`);
6
+ * - `IsDirectory`: a file operation met a directory;
7
+ * - `NotDirectory`: a directory operation met a file, or a path runs through one;
8
+ * - `NotEmpty`: a non-recursive `remove` of a directory with entries;
9
+ * - `Permission`: the backend refused access;
10
+ * - `Invalid`: the call itself is malformed (a relative path, a bad range or pattern, a symlink loop);
11
+ * - `Io`: anything else the backend reports.
12
+ */
13
+ export declare const FsReason: Schema.Literals<readonly ["NotFound", "Exists", "IsDirectory", "NotDirectory", "NotEmpty", "Permission", "Invalid", "Io"]>;
14
+ export type FsReason = typeof FsReason.Type;
15
+ declare const FsError_base: Schema.Class<FsError, Schema.TaggedStruct<"FsError", {
16
+ readonly path: Schema.String;
17
+ readonly reason: Schema.Literals<readonly ["NotFound", "Exists", "IsDirectory", "NotDirectory", "NotEmpty", "Permission", "Invalid", "Io"]>;
18
+ readonly message: Schema.String;
19
+ }>, import("effect/Cause").YieldableError>;
20
+ /** A failed file-system call: the path it was given, why, and the backend's message. */
21
+ export declare class FsError extends FsError_base {
22
+ }
23
+ /** What a path holds. `symlink` is reported only where links are not followed (`list`, `stat` with `followSymlinks: false`). */
24
+ export declare const FileKind: Schema.Literals<readonly ["file", "directory", "symlink", "other"]>;
25
+ export type FileKind = typeof FileKind.Type;
26
+ /** What `stat` reports. `path` is the path asked for; `mode` holds the permission bits where the backend has them. */
27
+ export declare const FileInfo: Schema.Struct<{
28
+ readonly path: Schema.String;
29
+ readonly kind: Schema.Literals<readonly ["file", "directory", "symlink", "other"]>;
30
+ readonly size: Schema.Number;
31
+ readonly mtimeMs: Schema.Number;
32
+ readonly mode: Schema.OptionFromOptionalKey<Schema.Int>;
33
+ }>;
34
+ export type FileInfo = typeof FileInfo.Type;
35
+ /** One entry of a directory listing; links are not followed. */
36
+ export declare const DirEntry: Schema.Struct<{
37
+ readonly name: Schema.String;
38
+ readonly kind: Schema.Literals<readonly ["file", "directory", "symlink", "other"]>;
39
+ }>;
40
+ export type DirEntry = typeof DirEntry.Type;
41
+ /** The bytes `readBytes` returns: from `offset` (default 0), at most `length` of them (default: to the end). */
42
+ export declare const ReadRange: Schema.Struct<{
43
+ readonly offset: Schema.optionalKey<Schema.Int>;
44
+ readonly length: Schema.optionalKey<Schema.Int>;
45
+ }>;
46
+ export type ReadRange = typeof ReadRange.Type;
47
+ /** `write` and `append`: with `createParents`, missing directories on the way are created first. */
48
+ export declare const WriteOptions: Schema.Struct<{
49
+ readonly createParents: Schema.optionalKey<Schema.Boolean>;
50
+ }>;
51
+ export type WriteOptions = typeof WriteOptions.Type;
52
+ /** `stat` follows symbolic links unless `followSymlinks` is false. */
53
+ export declare const StatOptions: Schema.Struct<{
54
+ readonly followSymlinks: Schema.optionalKey<Schema.Boolean>;
55
+ }>;
56
+ export type StatOptions = typeof StatOptions.Type;
57
+ /** `mkdir` and `remove`: `recursive` creates missing parents, or removes a directory with what it holds. */
58
+ export declare const RecursiveOptions: Schema.Struct<{
59
+ readonly recursive: Schema.optionalKey<Schema.Boolean>;
60
+ }>;
61
+ export type RecursiveOptions = typeof RecursiveOptions.Type;
62
+ /**
63
+ * How a glob walks. `cwd` is the absolute directory the pattern is relative
64
+ * to. `exclude` prunes entries anywhere in the walk: a pattern without a `/`
65
+ * is matched against each entry's name (`node_modules`, `*.log`), one with a
66
+ * `/` against its path relative to `cwd`; an excluded directory is not
67
+ * entered. Entries whose name starts with a dot are matched and entered only
68
+ * with `dot`, or where the pattern names them with a literal dot
69
+ * (`.github/**`). `onlyFiles` keeps regular files (not directories, links or
70
+ * other entries). The walk stops once it has found one more than `limit`
71
+ * paths, and reports `truncated`.
72
+ */
73
+ export declare const GlobOptions: Schema.Struct<{
74
+ readonly cwd: Schema.String;
75
+ readonly exclude: Schema.optionalKey<Schema.$Array<Schema.String>>;
76
+ readonly dot: Schema.optionalKey<Schema.Boolean>;
77
+ readonly onlyFiles: Schema.optionalKey<Schema.Boolean>;
78
+ readonly limit: Schema.optionalKey<Schema.Int>;
79
+ }>;
80
+ export type GlobOptions = typeof GlobOptions.Type;
81
+ /**
82
+ * What `glob` found: POSIX paths relative to its `cwd`, depth-first with each
83
+ * directory's entries by name (so a directory comes before what it holds),
84
+ * at most `limit` of them; `truncated` when more matched.
85
+ */
86
+ export declare const GlobResult: Schema.Struct<{
87
+ readonly paths: Schema.$Array<Schema.String>;
88
+ readonly truncated: Schema.Boolean;
89
+ }>;
90
+ export type GlobResult = typeof GlobResult.Type;
91
+ export {};
@@ -0,0 +1,18 @@
1
+ import { Effect } from "effect";
2
+ import { FsError } from "./file-system.entity.js";
3
+ import type { DirEntry, GlobOptions, GlobResult } from "./file-system.entity.js";
4
+ /**
5
+ * A glob as a walk over a directory listing, the one semantics every
6
+ * `FileSystem` backend shares (`fs.glob` differs between runtimes: it
7
+ * cannot list dot entries on Node and follows links on Bun). The walk is
8
+ * depth-first with each directory's entries sorted by name, so the paths
9
+ * come out in that order and a `limit` always keeps the same ones. It never
10
+ * enters a symbolic link, prunes `exclude`d entries before entering them,
11
+ * enters only directories that can hold a match, and stops at `limit + 1`
12
+ * matches to report `truncated`. A directory below `cwd` that cannot be
13
+ * listed (no permission, removed meanwhile) is skipped; `cwd` itself must
14
+ * list. The pattern is relative: an absolute one or one with a `..`
15
+ * segment fails with `Invalid`, as does a pattern (or an `exclude`) that
16
+ * `compileGlob` refuses.
17
+ */
18
+ export declare const walkGlob: (list: (dir: string) => Effect.Effect<ReadonlyArray<DirEntry>, FsError>, pattern: string, options: GlobOptions) => Effect.Effect<GlobResult, FsError>;
@@ -0,0 +1,30 @@
1
+ import { Chunk, Effect } from "effect";
2
+ import { compileGlob } from "../util/glob.js";
3
+ import { FsError } from "./file-system.entity.js";
4
+ const byName = (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0, under = (cwd, relative) => relative === "" ? cwd : cwd.endsWith("/") ? `${cwd}${relative}` : `${cwd}/${relative}`;
5
+ export const walkGlob = (list, pattern, options) => Effect.suspend(() => {
6
+ const { cwd } = options;
7
+ if (!cwd.startsWith("/"))
8
+ return Effect.fail(new FsError({ path: cwd, reason: "Invalid", message: "a glob's cwd must be an absolute path" }));
9
+ if (pattern.startsWith("/") || pattern.split("/").includes(".."))
10
+ return Effect.fail(new FsError({ path: pattern, reason: "Invalid", message: "a glob pattern is relative to its cwd and stays below it (no leading / or .. segment)" }));
11
+ const dot = options.dot ?? !1, onlyFiles = options.onlyFiles ?? !1, limit = options.limit ?? Number.POSITIVE_INFINITY, full = (found) => Chunk.size(found) > limit, compiled = (glob, dotted) => Effect.mapError(Effect.fromResult(compileGlob(glob, { dot: dotted })), (reason) => new FsError({ path: glob, reason: "Invalid", message: `not a usable glob pattern: ${reason}` }));
12
+ return Effect.all({
13
+ matcher: compiled(pattern, dot),
14
+ exclusions: Effect.forEach(options.exclude ?? [], (exclude) => compiled(exclude, !0).pipe(Effect.map((matcher) => ({ byPath: exclude.includes("/"), matches: matcher.matches }))))
15
+ }).pipe(Effect.flatMap(({ matcher, exclusions }) => {
16
+ const excluded = (name, path) => exclusions.some((exclusion) => exclusion.matches(exclusion.byPath ? path : name)), visit = (relative, found) => list(under(cwd, relative)).pipe(Effect.catchIf((error) => relative !== "" && (error.reason === "Permission" || error.reason === "NotFound"), () => Effect.succeed([])), Effect.flatMap((entries) => Effect.reduce(entries.toSorted(byName), () => found, (sofar, entry) => {
17
+ if (full(sofar))
18
+ return Effect.succeed(sofar);
19
+ const path = relative === "" ? entry.name : `${relative}/${entry.name}`;
20
+ if (excluded(entry.name, path))
21
+ return Effect.succeed(sofar);
22
+ const next = matcher.matches(path) && (!onlyFiles || entry.kind === "file") ? Chunk.append(sofar, path) : sofar;
23
+ return entry.kind === "directory" && !full(next) && matcher.descends(path) ? visit(path, next) : Effect.succeed(next);
24
+ })));
25
+ return visit("", Chunk.empty());
26
+ }), Effect.map((found) => ({
27
+ paths: Chunk.toReadonlyArray(Chunk.take(found, limit)),
28
+ truncated: full(found)
29
+ })));
30
+ });
@@ -0,0 +1,37 @@
1
+ import { Schema } from "effect";
2
+ export const FsReason = Schema.Literals(["NotFound", "Exists", "IsDirectory", "NotDirectory", "NotEmpty", "Permission", "Invalid", "Io"]);
3
+
4
+ export class FsError extends Schema.TaggedError()("FsError", {
5
+ path: Schema.String,
6
+ reason: FsReason,
7
+ message: Schema.String
8
+ }) {
9
+ }
10
+ export const FileKind = Schema.Literals(["file", "directory", "symlink", "other"]), FileInfo = Schema.Struct({
11
+ path: Schema.String,
12
+ kind: FileKind,
13
+ size: Schema.Number,
14
+ mtimeMs: Schema.Number,
15
+ mode: Schema.OptionFromOptionalKey(Schema.Int)
16
+ }), DirEntry = Schema.Struct({
17
+ name: Schema.String,
18
+ kind: FileKind
19
+ }), ReadRange = Schema.Struct({
20
+ offset: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),
21
+ length: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)))
22
+ }), WriteOptions = Schema.Struct({
23
+ createParents: Schema.optionalKey(Schema.Boolean)
24
+ }), StatOptions = Schema.Struct({
25
+ followSymlinks: Schema.optionalKey(Schema.Boolean)
26
+ }), RecursiveOptions = Schema.Struct({
27
+ recursive: Schema.optionalKey(Schema.Boolean)
28
+ }), GlobOptions = Schema.Struct({
29
+ cwd: Schema.String,
30
+ exclude: Schema.optionalKey(Schema.Array(Schema.String)),
31
+ dot: Schema.optionalKey(Schema.Boolean),
32
+ onlyFiles: Schema.optionalKey(Schema.Boolean),
33
+ limit: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)))
34
+ }), GlobResult = Schema.Struct({
35
+ paths: Schema.Array(Schema.String),
36
+ truncated: Schema.Boolean
37
+ });
@@ -70,6 +70,15 @@ export type LoopEvent = {
70
70
  /** The schema-encoded result — the persisted, provider-visible form. */
71
71
  readonly encoded?: unknown;
72
72
  }
73
+ /** A streamed call failed before its first part: this step, and every
74
+ * later step of the run, is answered by `generateText` instead. Once per
75
+ * run at most; `message` is the stream's error as text, cut to 300
76
+ * characters. */
77
+ | {
78
+ readonly type: "stream_fallback";
79
+ readonly turnIndex: number;
80
+ readonly message: string;
81
+ }
73
82
  /** The mid-run fold: the buffer outgrew the healthy context range and the
74
83
  * older turns were replaced by a handoff summary — `kept` verbatim
75
84
  * messages survive after it. A load-side rewrite; nothing is deleted. */
@@ -0,0 +1,79 @@
1
+ import { Schema } from "effect";
2
+ /**
3
+ * Images a model can be shown: a user's attachments (and, later, what a tool
4
+ * returns). An image is stored inline in the session log, as base64, once;
5
+ * these limits keep one image, one message and one request inside what the
6
+ * providers accept and what a session store must hold.
7
+ */
8
+ export declare const MEDIA_LIMITS: {
9
+ /** Decoded bytes of one image: 3.75 MiB, 5 242 880 base64 characters (Anthropic's per-image limit). */
10
+ readonly imageBytes: 3932160;
11
+ /** Pixels on either side of one image. */
12
+ readonly maxPixels: 8000;
13
+ /** Attachments on one user message. */
14
+ readonly attachments: 8;
15
+ /** Images one request sends as images (the rest are label lines). */
16
+ readonly requestImages: 8;
17
+ /** Base64 characters of the images one request sends, and of one message's attachments together. */
18
+ readonly requestChars: 20000000;
19
+ /** Images one tool result may carry. */
20
+ readonly toolResultImages: 4;
21
+ };
22
+ /** The image types every provider route that takes images accepts. */
23
+ export declare const ImageMediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
24
+ export type ImageMediaType = typeof ImageMediaType.Type;
25
+ /**
26
+ * A content hash of an image's decoded bytes (an FNV-1a lane and a
27
+ * multiply-xorshift lane, 32 bits each, then the length, in hex). It names an
28
+ * image in slots and fingerprints; it is not cryptographic.
29
+ */
30
+ export declare const MediaFingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
31
+ export type MediaFingerprint = typeof MediaFingerprint.Type;
32
+ /**
33
+ * One image, inline: padded base64 `data` (no `data:` prefix) of `bytes`
34
+ * decoded bytes, of the `mediaType` its bytes are. Build one with
35
+ * `mediaFromBytes` or `mediaFromBase64`, which check the bytes and set the
36
+ * type, size and fingerprint from them.
37
+ */
38
+ export declare const Media: Schema.Struct<{
39
+ readonly type: Schema.Literal<"media">;
40
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
41
+ readonly data: Schema.String;
42
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
43
+ readonly bytes: Schema.Int;
44
+ /** A file name the user or tool gave it, shown in its label. */
45
+ readonly name: Schema.optionalKey<Schema.String>;
46
+ /** A description of the image, shown in its label. */
47
+ readonly alt: Schema.optionalKey<Schema.String>;
48
+ }>;
49
+ export type Media = typeof Media.Type;
50
+ /** Where an image sits inside a JSON value (a tool's encoded result): its path and what it must be. */
51
+ export declare const MediaSlot: Schema.Struct<{
52
+ readonly path: Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Int]>>;
53
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
54
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
55
+ readonly bytes: Schema.Int;
56
+ }>;
57
+ export type MediaSlot = typeof MediaSlot.Type;
58
+ /**
59
+ * Why an image was refused: no bytes (`Empty`), data that is not base64
60
+ * (`InvalidBase64`), bytes that are none of the image types
61
+ * (`UnsupportedType`), more than `MEDIA_LIMITS.imageBytes` (`TooLarge`), a
62
+ * side over `MEDIA_LIMITS.maxPixels` (`TooManyPixels`), a header whose size
63
+ * cannot be read (`Unreadable`), or attachments over
64
+ * `MEDIA_LIMITS.requestChars` together (`TooLargeTogether`). `TooMany` is
65
+ * defensive: a `UserMessage` with more than `MEDIA_LIMITS.attachments` fails
66
+ * its schema when it is constructed or decoded, so only a value that skipped
67
+ * that check reaches a begin with too many.
68
+ */
69
+ export declare const AttachmentRejectedReason: Schema.Literals<readonly ["Empty", "InvalidBase64", "UnsupportedType", "TooLarge", "TooManyPixels", "Unreadable", "TooMany", "TooLargeTogether"]>;
70
+ export type AttachmentRejectedReason = typeof AttachmentRejectedReason.Type;
71
+ declare const AttachmentRejected_base: Schema.Class<AttachmentRejected, Schema.TaggedStruct<"AttachmentRejected", {
72
+ readonly reason: Schema.Literals<readonly ["Empty", "InvalidBase64", "UnsupportedType", "TooLarge", "TooManyPixels", "Unreadable", "TooMany", "TooLargeTogether"]>;
73
+ readonly index: Schema.optionalKey<Schema.Int>;
74
+ readonly message: Schema.String;
75
+ }>, import("effect/Cause").YieldableError>;
76
+ /** An image a user message or a tool result cannot carry; `index` is the attachment's position, when it is one image's fault. */
77
+ export declare class AttachmentRejected extends AttachmentRejected_base {
78
+ }
79
+ export {};
@@ -0,0 +1,76 @@
1
+ import { Effect, Option } from "effect";
2
+ import { AttachmentRejected, ImageMediaType, MediaFingerprint } from "./media.entity.js";
3
+ import type { Media, MediaSlot } from "./media.entity.js";
4
+ /** What one image is counted as in a token estimate: its base64 is never counted as text. */
5
+ export declare const IMAGE_TOKEN_ESTIMATE = 1600;
6
+ /** The base64 characters `bytes` decoded bytes take, padded. */
7
+ export declare const base64Length: (bytes: number) => number;
8
+ /** An image's size in pixels, read from its header. */
9
+ export interface ImageSize {
10
+ readonly width: number;
11
+ readonly height: number;
12
+ }
13
+ /** What a caller may say about an image besides its bytes. */
14
+ export interface MediaDescription {
15
+ readonly name?: string;
16
+ readonly alt?: string;
17
+ }
18
+ /** The image type the bytes are, from their magic numbers: PNG, JPEG, GIF or WebP. */
19
+ export declare const sniffImageType: (bytes: Uint8Array) => Option.Option<ImageMediaType>;
20
+ /** An image's size in pixels from its header (PNG IHDR, GIF screen, WebP VP8/VP8L/VP8X, JPEG frame); none when the header is not readable. */
21
+ export declare const imageSizeOf: (bytes: Uint8Array, mediaType: ImageMediaType) => Option.Option<ImageSize>;
22
+ /** FNV-1a and a multiply-xorshift lane over the bytes, then their length: a content hash, not a cryptographic one. */
23
+ export declare const mediaFingerprintOf: (bytes: Uint8Array) => MediaFingerprint;
24
+ /**
25
+ * An image from its bytes. The type is the one the bytes are (sniffed), the
26
+ * size and fingerprint are computed, and the header must give a size of at
27
+ * most `MEDIA_LIMITS.maxPixels` a side. Fails with `AttachmentRejected`.
28
+ */
29
+ export declare const mediaFromBytes: (bytes: Uint8Array, description?: MediaDescription) => Effect.Effect<Media, AttachmentRejected>;
30
+ /**
31
+ * An image from base64, as `mediaFromBytes` checks it. A `data:` URL prefix
32
+ * and whitespace (wrapped lines) are removed first; the stored `data` is the
33
+ * canonical padded base64 of the bytes.
34
+ */
35
+ export declare const mediaFromBase64: (data: string, description?: MediaDescription) => Effect.Effect<Media, AttachmentRejected>;
36
+ /** An image checked again from its own data: type, size and fingerprint as its bytes give them; its name and alt kept. */
37
+ export declare const normalizeMedia: (media: Media) => Effect.Effect<Media, AttachmentRejected>;
38
+ /**
39
+ * The one line that stands for an image a request or a transcript does not
40
+ * carry: `[image omitted: image/png, 182 KB, shot.png: a chart]`.
41
+ */
42
+ export declare const mediaLabel: (media: Pick<Media, "mediaType" | "bytes" | "name" | "alt">) => string;
43
+ /** A cheap structural check that a value is a `Media` (no base64 or fingerprint validation). */
44
+ export declare const isMediaValue: (value: unknown) => value is Media;
45
+ /** Every image inside a JSON value, in key-sorted order, with its path. */
46
+ export declare const mediaSlotsOf: (value: unknown) => ReadonlyArray<MediaSlot>;
47
+ /**
48
+ * The image a slot names inside a JSON value, when the value there is an
49
+ * image with the slot's fingerprint, type and size. Compares the stored
50
+ * fields only: an image's content is checked once, when it is written.
51
+ */
52
+ export declare const mediaAt: (value: unknown, slot: MediaSlot) => Option.Option<Media>;
53
+ /** A tool result's images as memory records them: the slots it sends, and a label line for each image it does not. */
54
+ export interface ToolResultMedia {
55
+ readonly slots: ReadonlyArray<MediaSlot>;
56
+ readonly labels: ReadonlyArray<string>;
57
+ }
58
+ /**
59
+ * A tool result's images checked once, when memory writes the result (a
60
+ * provider refuses a request with a bad image, and every later request
61
+ * would carry it). In slot order, each slot must name an image of the
62
+ * encoded value, its data base64 of an image whose type, size and
63
+ * fingerprint are the ones it states (`normalizeMedia` gives them back
64
+ * unchanged); an image that fails is an `[image unavailable: <why>]` line.
65
+ * An image a slot already named is sent once. At most
66
+ * `MEDIA_LIMITS.toolResultImages` images are sent, within
67
+ * `MEDIA_LIMITS.requestChars` base64 characters together; one over that is
68
+ * its `mediaLabel` line.
69
+ */
70
+ export declare const toolResultMedia: (encoded: unknown, slots: ReadonlyArray<MediaSlot>) => Effect.Effect<ToolResultMedia>;
71
+ /**
72
+ * A JSON value with every image's `data` replaced by its fingerprint: what
73
+ * text search, fingerprints, estimates and traces see of an image. Parts
74
+ * without an image are returned as they are (the same objects).
75
+ */
76
+ export declare const elideMediaData: (value: unknown) => unknown;