@xandreed/core 0.12.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 (155) 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 -10
  37. package/dist/index.js +67 -14
  38. package/dist/loop/cacheKey.d.ts +1 -1
  39. package/dist/loop/mapping.d.ts +13 -7
  40. package/dist/loop/mapping.js +30 -6
  41. package/dist/loop/stepContext.d.ts +8 -0
  42. package/dist/loop/stepContext.js +1 -1
  43. package/dist/loop/traceContent.d.ts +29 -0
  44. package/dist/loop/traceContent.js +4 -0
  45. package/dist/loop/traceContent.test.d.ts +1 -0
  46. package/dist/memory/memory-log.entity.d.ts +152 -14
  47. package/dist/memory/memory-log.entity.functions.d.ts +35 -5
  48. package/dist/memory/memory-log.entity.functions.js +59 -20
  49. package/dist/memory/memory-log.entity.js +19 -6
  50. package/dist/memory/memory-session.js +10 -6
  51. package/dist/memory/memory.conformance.d.ts +8 -1
  52. package/dist/memory/memory.conformance.js +32 -0
  53. package/dist/models/auth-store.conformance.d.ts +13 -0
  54. package/dist/models/auth-store.conformance.js +73 -0
  55. package/dist/models/auth-store.conformance.test.d.ts +1 -0
  56. package/dist/models/model-catalog.conformance.d.ts +15 -0
  57. package/dist/models/model-catalog.conformance.js +27 -0
  58. package/dist/models/model-catalog.conformance.test.d.ts +1 -0
  59. package/dist/models/settings-store.conformance.d.ts +26 -0
  60. package/dist/models/settings-store.conformance.js +80 -0
  61. package/dist/models/settings-store.conformance.test.d.ts +1 -0
  62. package/dist/ports/activity.port.d.ts +35 -0
  63. package/dist/ports/activity.port.js +7 -0
  64. package/dist/ports/auth-store.port.d.ts +7 -5
  65. package/dist/ports/bash.port.d.ts +22 -0
  66. package/dist/ports/bash.port.js +4 -0
  67. package/dist/ports/capability.port.d.ts +11 -1
  68. package/dist/ports/file-system.port.d.ts +44 -15
  69. package/dist/ports/file-system.port.js +1 -7
  70. package/dist/ports/harness.port.d.ts +1 -99
  71. package/dist/ports/harness.port.js +0 -24
  72. package/dist/ports/memory.port.d.ts +13 -1
  73. package/dist/ports/model-catalog.port.d.ts +4 -1
  74. package/dist/ports/run-context.port.d.ts +6 -1
  75. package/dist/ports/session-log.port.d.ts +4 -1
  76. package/dist/ports/sessions.port.d.ts +35 -6
  77. package/dist/ports/settings-store.port.d.ts +11 -7
  78. package/dist/ports/step-loop.port.d.ts +30 -2
  79. package/dist/ports/tasks.port.d.ts +5 -1
  80. package/dist/ports/turn-admission.port.d.ts +8 -2
  81. package/dist/ports/turn-events.port.d.ts +8 -1
  82. package/dist/ports/turn-scope.port.d.ts +19 -1
  83. package/dist/ports/turn.port.d.ts +70 -5
  84. package/dist/ports/utility-llm.port.d.ts +2 -0
  85. package/dist/session/activity.entity.d.ts +42 -0
  86. package/dist/session/activity.entity.functions.d.ts +21 -0
  87. package/dist/session/activity.entity.functions.js +23 -0
  88. package/dist/session/activity.entity.functions.test.d.ts +1 -0
  89. package/dist/session/activity.entity.js +15 -0
  90. package/dist/session/chassis.js +2 -1
  91. package/dist/session/session-event.entity.d.ts +68 -6
  92. package/dist/session/session-event.entity.functions.d.ts +34 -2
  93. package/dist/session/session-event.entity.functions.js +54 -16
  94. package/dist/session/session-event.entity.js +19 -2
  95. package/dist/session/session-log.conformance.d.ts +4 -3
  96. package/dist/session/session-log.conformance.js +16 -14
  97. package/dist/session/session-log.recovery.conformance.d.ts +40 -0
  98. package/dist/session/session-log.recovery.conformance.js +143 -0
  99. package/dist/session/session-log.recovery.conformance.test.d.ts +1 -0
  100. package/dist/session/sessions.conformance.d.ts +79 -0
  101. package/dist/session/sessions.conformance.js +355 -0
  102. package/dist/session/sessions.entity.d.ts +36 -3
  103. package/dist/session/sessions.entity.functions.d.ts +42 -0
  104. package/dist/session/sessions.entity.functions.js +26 -0
  105. package/dist/session/sessions.entity.js +17 -4
  106. package/dist/session/sessions.entity.test.d.ts +1 -0
  107. package/dist/session/tasks.conformance.d.ts +70 -0
  108. package/dist/session/tasks.conformance.js +213 -0
  109. package/dist/session/tasks.conformance.test.d.ts +1 -0
  110. package/dist/turn/model-request.entity.d.ts +4 -0
  111. package/dist/turn/model-request.entity.js +7 -2
  112. package/dist/turn/step-loop.conformance.d.ts +4 -1
  113. package/dist/turn/step-loop.conformance.js +73 -7
  114. package/dist/turn/tool-registry.conformance.d.ts +38 -0
  115. package/dist/turn/tool-registry.conformance.js +206 -0
  116. package/dist/turn/turn-bus.js +4 -3
  117. package/dist/turn/turn-event.entity.d.ts +134 -34
  118. package/dist/turn/turn-event.entity.functions.d.ts +11 -0
  119. package/dist/turn/turn-event.entity.functions.js +9 -1
  120. package/dist/turn/turn-event.entity.js +76 -3
  121. package/dist/turn/turn-event.entity.test.d.ts +1 -0
  122. package/dist/turn/turn-lifecycle.d.ts +46 -8
  123. package/dist/turn/turn-lifecycle.js +33 -3
  124. package/dist/turn/turn-lifecycle.test.d.ts +1 -0
  125. package/dist/turn/turn-run.d.ts +15 -3
  126. package/dist/turn/turn-run.js +37 -9
  127. package/dist/turn/turn.adapter.d.ts +6 -5
  128. package/dist/turn/turn.adapter.js +15 -3
  129. package/dist/turn/turn.conformance.d.ts +11 -2
  130. package/dist/turn/turn.conformance.js +63 -2
  131. package/dist/turn/user-message.entity.d.ts +14 -4
  132. package/dist/turn/user-message.entity.functions.d.ts +21 -0
  133. package/dist/turn/user-message.entity.functions.js +24 -0
  134. package/dist/turn/user-message.entity.js +6 -8
  135. package/dist/turn/user-message.entity.test.d.ts +1 -0
  136. package/dist/util/glob.d.ts +30 -0
  137. package/dist/util/glob.js +91 -0
  138. package/dist/util/glob.test.d.ts +1 -0
  139. package/dist/workspace/bash.conformance.d.ts +37 -0
  140. package/dist/workspace/bash.conformance.js +120 -0
  141. package/dist/workspace/bash.conformance.test.d.ts +1 -0
  142. package/dist/workspace/file-system.conformance.d.ts +38 -0
  143. package/dist/workspace/file-system.conformance.js +254 -0
  144. package/dist/workspace/file-system.conformance.test.d.ts +1 -0
  145. package/dist/workspace/file-system.memory.adapter.d.ts +23 -0
  146. package/dist/workspace/file-system.memory.adapter.js +132 -0
  147. package/package.json +6 -6
  148. package/dist/harness/session.entity.d.ts +0 -33
  149. package/dist/harness/session.entity.js +0 -25
  150. package/dist/harness/skill-files.d.ts +0 -17
  151. package/dist/harness/skill-files.js +0 -25
  152. package/dist/ports/conversation-store.port.d.ts +0 -127
  153. package/dist/ports/conversation-store.port.js +0 -36
  154. package/dist/ports/shell.port.d.ts +0 -32
  155. package/dist/ports/shell.port.js +0 -16
@@ -1,6 +1,6 @@
1
1
  import { Context, Option } from "effect";
2
2
  /**
3
- * The CURRENT conversation's cache identity, stamped by `runAgent` for the
3
+ * The CURRENT conversation's cache identity, stamped by the step loop for the
4
4
  * duration of a run. Adapters that can key server-side prompt caches on a
5
5
  * stable id (OpenAI-compatible `prompt_cache_key`) read it at call time —
6
6
  * one conversation, one cache lane, so parallel sessions stop evicting
@@ -1,7 +1,7 @@
1
1
  import { Option } from "effect";
2
2
  import type { ToolCallSummary } from "../domain/loop-event.entity.js";
3
3
  import type { AgentMessage } from "../domain/message.entity.js";
4
- import type { TokenUsage } from "../domain/token-usage.entity.js";
4
+ import { TokenUsage } from "../domain/token-usage.entity.js";
5
5
  /**
6
6
  * Bridges the persisted `AgentMessage` with `@effect/ai`'s `Prompt`/`Response`
7
7
  * encodings. The opaque provider blob is carried verbatim both ways —
@@ -11,7 +11,7 @@ import type { TokenUsage } from "../domain/token-usage.entity.js";
11
11
  * by hand and keeps the blob). Everything here is pure: no mutation, no IO.
12
12
  */
13
13
  /** Wrap a fold summary as the single user message standing in for the folded
14
- * history — prepended by `runAgent` when the conversation has a checkpoint. */
14
+ * history — prepended when memory replays a conversation from a checkpoint. */
15
15
  export declare const handoffToMessage: (summary: string) => AgentMessage;
16
16
  /**
17
17
  * The largest SAFE fold cut keeping at least `keepTurns` assistant turns
@@ -21,7 +21,7 @@ export declare const handoffToMessage: (summary: string) => AgentMessage;
21
21
  * small to fold at all.
22
22
  */
23
23
  export declare const safeKeepFrom: (messages: ReadonlyArray<AgentMessage>, keepTurns: number) => Option.Option<number>;
24
- /** `AgentMessage[]` → `@effect/ai` encoded prompt messages (spreadable). */
24
+ /** `AgentMessage[]` → `@effect/ai` encoded prompt messages (spreadable). A text-only user message stays a string. */
25
25
  export declare const toPromptMessages: (messages: ReadonlyArray<AgentMessage>) => ReadonlyArray<unknown>;
26
26
  /**
27
27
  * Some providers (notably Gemini) return tool calls WITHOUT an id. An absent
@@ -58,9 +58,14 @@ export interface ToolResultSummary {
58
58
  export declare const responseToolResults: (content: ReadonlyArray<unknown>) => ReadonlyArray<ToolResultSummary>;
59
59
  /**
60
60
  * Token usage from a response's `usage` + the finish part's. Effect's
61
- * providers report the FULL input (cache reads and writes included, e.g.
62
- * Anthropic's `input_tokens` plus both cache counts) with the cache reads
63
- * beside it; Gemini's raw usage metadata is the last fallback.
61
+ * providers report the FULL input with the cache reads and writes inside it
62
+ * (Anthropic's `input_tokens` plus both cache counts; OpenAI's
63
+ * `input_tokens`, whose `input_tokens_details` give the cached and written
64
+ * shares) and the full output with the reasoning inside it. Each count is
65
+ * read from the response's usage, then the finish part's; the result holds
66
+ * the `TokenUsage` invariants (`tokenUsage`), so an output reported below
67
+ * its reasoning is raised to it. Gemini's raw usage metadata is the last
68
+ * fallback: its output is candidates plus thoughts, the thoughts as reasoning.
64
69
  */
65
70
  export declare const extractUsage: (usage: unknown, content: ReadonlyArray<unknown>) => TokenUsage;
66
71
  /**
@@ -72,7 +77,8 @@ export declare const extractUsage: (usage: unknown, content: ReadonlyArray<unkno
72
77
  export declare const withUsageOnAssistant: (messages: ReadonlyArray<AgentMessage>, usage: TokenUsage, model?: Option.Option<string>) => ReadonlyArray<AgentMessage>;
73
78
  /** The resolved `provider:modelId` the router stamped onto the finish part. */
74
79
  export declare const extractModel: (content: ReadonlyArray<unknown>) => Option.Option<string>;
75
- /** The turn usage embedded on a persisted assistant message, if any. */
80
+ /** The turn usage embedded on a persisted assistant message, if any,
81
+ * decoded: a stamp written before 0.14.0 reads 0 cache-write and reasoning tokens. */
76
82
  export declare const assistantUsage: (msg: AgentMessage) => Option.Option<TokenUsage>;
77
83
  /** The `provider:modelId` embedded alongside the usage stamp, if any. */
78
84
  export declare const assistantModel: (msg: AgentMessage) => Option.Option<string>;
@@ -1,5 +1,7 @@
1
- import { Option } from "effect";
1
+ import { Option, Schema } from "effect";
2
2
  import { ToolCallId } from "../domain/message.entity.js";
3
+ import { TokenUsage } from "../domain/token-usage.entity.js";
4
+ import { tokenUsage } from "../domain/token-usage.entity.functions.js";
3
5
  export const handoffToMessage = (summary) => ({
4
6
  role: "user",
5
7
  content: `[System note: the earlier history of this conversation has been handed off into the summary below to free up context. Treat the summary as the source of truth for everything before this point.]
@@ -17,10 +19,15 @@ const hasKeys = (o) => typeof o === "object" && o !== null && Object.keys(o).len
17
19
  return blob;
18
20
  const { [USAGE_KEY]: _engine, ...rest } = blob;
19
21
  return rest;
22
+ }, filePart = (media) => ({ type: "file", mediaType: media.mediaType, data: media.data, ...media.name === void 0 ? {} : { fileName: media.name } }), userPromptParts = (parts) => parts.flatMap((part) => part.type === "text" ? part.text.length === 0 ? [] : [{ type: "text", text: part.text, ...withOptions(part.providerOptions) }] : [filePart(part)]), toolModelOutput = (output, media) => {
23
+ if (media === void 0 || media.length === 0)
24
+ return {};
25
+ const text = typeof output === "string" ? output : JSON.stringify(output ?? null);
26
+ return { modelOutput: [...text.length === 0 ? [] : [{ type: "text", text }], ...media.map(filePart)] };
20
27
  };
21
28
  export const toPromptMessages = (messages) => messages.map((m) => {
22
29
  if (m.role === "user")
23
- return { role: "user", content: m.content };
30
+ return { role: "user", content: typeof m.content === "string" ? m.content : userPromptParts(m.content) };
24
31
  if (m.role === "assistant")
25
32
  return {
26
33
  role: "assistant",
@@ -47,6 +54,7 @@ export const toPromptMessages = (messages) => messages.map((m) => {
47
54
  id: p.toolCallId,
48
55
  name: p.toolName,
49
56
  result: p.output,
57
+ ...toolModelOutput(p.output, p.media),
50
58
  isFailure: p.isError ?? !1,
51
59
  providerExecuted: !1,
52
60
  ...withOptions(p.providerOptions)
@@ -117,8 +125,22 @@ export const responseToolResults = (content) => content.filter((p) => p.type ===
117
125
  }));
118
126
  const carriesUsage = (usage) => usage?.inputTokens?.total !== void 0 || usage?.outputTokens?.total !== void 0;
119
127
  export const extractUsage = (usage, content) => {
120
- const u = usage ?? {}, finishes = content.filter((p) => p.type === "finish"), finish = finishes.find((p) => carriesUsage(p.usage)) ?? finishes[0], gm = finish?.metadata?.google?.usageMetadata, fu = finish?.usage, inputTokens = u.inputTokens?.total ?? fu?.inputTokens?.total ?? gm?.promptTokenCount ?? 0, outputTokens = u.outputTokens?.total ?? fu?.outputTokens?.total ?? gm?.candidatesTokenCount ?? 0, totalTokens = carriesUsage(u) || carriesUsage(fu) ? inputTokens + outputTokens : gm?.totalTokenCount ?? 0, cacheReadTokens = u.inputTokens?.cacheRead ?? fu?.inputTokens?.cacheRead ?? gm?.cachedContentTokenCount ?? 0;
121
- return { inputTokens, outputTokens, totalTokens, cacheReadTokens };
128
+ const u = usage ?? {}, finishes = content.filter((p) => p.type === "finish"), finish = finishes.find((p) => carriesUsage(p.usage)) ?? finishes[0], fu = finish?.usage;
129
+ if (carriesUsage(u) || carriesUsage(fu))
130
+ return tokenUsage({
131
+ inputTokens: u.inputTokens?.total ?? fu?.inputTokens?.total ?? 0,
132
+ outputTokens: u.outputTokens?.total ?? fu?.outputTokens?.total ?? 0,
133
+ cacheReadTokens: u.inputTokens?.cacheRead ?? fu?.inputTokens?.cacheRead ?? 0,
134
+ cacheWriteTokens: u.inputTokens?.cacheWrite ?? fu?.inputTokens?.cacheWrite ?? 0,
135
+ reasoningTokens: u.outputTokens?.reasoning ?? fu?.outputTokens?.reasoning ?? 0
136
+ });
137
+ const gm = finish?.metadata?.google?.usageMetadata, thoughts = gm?.thoughtsTokenCount ?? 0;
138
+ return tokenUsage({
139
+ inputTokens: gm?.promptTokenCount ?? 0,
140
+ outputTokens: (gm?.candidatesTokenCount ?? 0) + thoughts,
141
+ cacheReadTokens: gm?.cachedContentTokenCount ?? 0,
142
+ reasoningTokens: thoughts
143
+ });
122
144
  }, withUsageOnAssistant = (messages, usage, model = Option.none()) => {
123
145
  const at = messages.findIndex((m) => m.role === "assistant"), stamp = {
124
146
  ...usage,
@@ -133,11 +155,13 @@ export const extractUsage = (usage, content) => {
133
155
  }, extractModel = (content) => {
134
156
  const model = content.find((p) => p.type === "finish")?.metadata?.router?.model;
135
157
  return typeof model === "string" && model.length > 0 ? Option.some(model) : Option.none();
136
- }, assistantUsage = (msg) => {
158
+ };
159
+ const decodeUsage = Schema.decodeUnknownOption(TokenUsage);
160
+ export const assistantUsage = (msg) => {
137
161
  if (msg.role !== "assistant")
138
162
  return Option.none();
139
163
  const usage = msg.providerOptions?.[USAGE_KEY];
140
- return hasKeys(usage) ? Option.some(usage) : Option.none();
164
+ return hasKeys(usage) ? decodeUsage(usage) : Option.none();
141
165
  }, assistantModel = (msg) => {
142
166
  if (msg.role !== "assistant")
143
167
  return Option.none();
@@ -1,3 +1,11 @@
1
1
  import { Context, Option } from "effect";
2
2
  /** Correlation only; unset for work outside the agent loop. */
3
3
  export declare const CurrentAgentStep: Context.Reference<Option.Option<number>>;
4
+ /** The tool call a handler is running for: the ids its `tool.started`, `tool.progress` and `tool.completed` events share. */
5
+ export interface ToolInvocation {
6
+ readonly invocationId: string;
7
+ readonly tool: string;
8
+ readonly step: number;
9
+ }
10
+ /** Set by the tool registry around each handler call; none outside a tool. */
11
+ export declare const CurrentToolInvocation: Context.Reference<Option.Option<ToolInvocation>>;
@@ -1,2 +1,2 @@
1
1
  import { Context, Option } from "effect";
2
- export const CurrentAgentStep = Context.Reference("@xandreed/core/CurrentAgentStep", { defaultValue: () => Option.none() });
2
+ export const CurrentAgentStep = Context.Reference("@xandreed/core/CurrentAgentStep", { defaultValue: () => Option.none() }), CurrentToolInvocation = Context.Reference("@xandreed/core/CurrentToolInvocation", { defaultValue: () => Option.none() });
@@ -0,0 +1,29 @@
1
+ import { Context } from "effect";
2
+ /**
3
+ * Whether spans may carry prompt and response content: the step loop's
4
+ * `engine.step.input` and `engine.step.output`, the models plugin's
5
+ * `llm.reasoning`. Off by default. Read per call, never when a layer is
6
+ * built: the step loop provides it for each run from
7
+ * `StepRequest.captureTraceContent` (the policy's `captureTraceContent`,
8
+ * else the agent's, else this reference where the run starts). Hosts own
9
+ * consent, masking and exporter retention.
10
+ *
11
+ * A context reference, like `CurrentPromptCacheKey`: ambient call metadata
12
+ * that flows through the loop's fibers without threading a parameter.
13
+ */
14
+ export declare const CurrentTraceContent: Context.Reference<boolean>;
15
+ /**
16
+ * A context captured to be provided again later (the services a layer was
17
+ * built with, the services where a turn's tools were opened), without the
18
+ * trace state of the place it was captured, so the work it runs is traced
19
+ * where that work runs:
20
+ * - the parent span (`Tracer.ParentSpan`): spans nest under the span current
21
+ * where the work runs, not under the span current at capture;
22
+ * - the span annotations and links (`Effect.annotateSpans`,
23
+ * `Effect.linkSpans`): providing the captured ones would replace those of
24
+ * where the work runs, the turn's ids among them;
25
+ * - `CurrentTraceContent`, which is read per call.
26
+ * The work then runs with the values of the fiber it runs in. Removing
27
+ * these keys removes nothing the context's type names.
28
+ */
29
+ export declare const replayableContext: <S>(context: Context.Context<S>) => Context.Context<S>;
@@ -0,0 +1,4 @@
1
+ import { Context, References, Tracer } from "effect";
2
+ export const CurrentTraceContent = Context.Reference("@xandreed/core/CurrentTraceContent", {
3
+ defaultValue: () => !1
4
+ }), replayableContext = (context) => Context.omit(Tracer.ParentSpan, References.TracerSpanAnnotations, References.TracerSpanLinks, CurrentTraceContent)(context);
@@ -0,0 +1 @@
1
+ export {};
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { UserMessage } from "../turn/user-message.entity.js";
2
3
  /**
3
4
  * The conversation memory log — the single source every model request is
4
5
  * rebuilt from ("model-visible ⟺ logged"). Entries are appended, never edited:
@@ -16,7 +17,12 @@ export declare const Subject: Schema.Struct<{
16
17
  readonly data: Schema.OptionFromNullOr<Schema.Unknown>;
17
18
  }>;
18
19
  export type Subject = typeof Subject.Type;
19
- /** A file or image a tool result carries, kept by reference (never inlined in the log). */
20
+ /**
21
+ * A file or image a tool result points to by URL: the log keeps the
22
+ * reference, never the content, and every render shows it as a reference
23
+ * line, whatever the media mode. An image the model is to see is a `Media`
24
+ * value, stored inline.
25
+ */
20
26
  export declare const ArtifactRef: Schema.Struct<{
21
27
  readonly id: Schema.Trimmed;
22
28
  readonly kind: Schema.Literals<readonly ["image", "file"]>;
@@ -37,6 +43,9 @@ export declare const CompactionAction: Schema.Union<readonly [Schema.TaggedStruc
37
43
  }>, Schema.TaggedStruct<"Summarize", {
38
44
  readonly keepFromTurn: Schema.Int;
39
45
  readonly summary: Schema.String;
46
+ }>, Schema.TaggedStruct<"OmitMedia", {
47
+ readonly entries: Schema.$Array<Schema.brand<Schema.Trimmed, "EntryId">>;
48
+ readonly reason: Schema.String;
40
49
  }>]>;
41
50
  export type CompactionAction = typeof CompactionAction.Type;
42
51
  export declare const ActivationSource: Schema.Literals<readonly ["always", "matcher", "load_skill", "host"]>;
@@ -49,18 +58,40 @@ export declare const LogBody: Schema.Union<readonly [Schema.TaggedStruct<"System
49
58
  readonly version: Schema.String;
50
59
  readonly fingerprint: Schema.String;
51
60
  }>>;
52
- }>, Schema.encodeKeys<Schema.TaggedStruct<"TurnStarted", {
53
- readonly userMessage: Schema.decodeTo<typeof import("@xandreed/sdk").UserMessage, Schema.String, never, never>;
54
- }>, {
55
- readonly userMessage: "prompt";
56
- }>, Schema.TaggedStruct<"TurnContext", {
61
+ }>, Schema.decodeTo<Schema.TaggedStruct<"TurnStarted", {
62
+ readonly userMessage: typeof UserMessage;
63
+ }>, Schema.Struct<{
64
+ readonly _tag: Schema.Literal<"TurnStarted">;
65
+ readonly prompt: Schema.String;
66
+ readonly attachments: Schema.optionalKey<Schema.$Array<Schema.toEncoded<Schema.Struct<{
67
+ readonly type: Schema.Literal<"media">;
68
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
69
+ readonly data: Schema.String;
70
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
71
+ readonly bytes: Schema.Int;
72
+ readonly name: Schema.optionalKey<Schema.String>;
73
+ readonly alt: Schema.optionalKey<Schema.String>;
74
+ }>>>>;
75
+ }>, never, never>, Schema.TaggedStruct<"TurnContext", {
57
76
  readonly sectionId: Schema.String;
58
77
  readonly version: Schema.String;
59
78
  readonly text: Schema.String;
60
79
  }>, Schema.TaggedStruct<"Message", {
61
80
  readonly message: Schema.Union<readonly [Schema.Struct<{
62
81
  readonly role: Schema.Literal<"user">;
63
- readonly content: Schema.String;
82
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{
83
+ readonly type: Schema.Literal<"text">;
84
+ readonly text: Schema.String;
85
+ readonly providerOptions: Schema.optional<Schema.Unknown>;
86
+ }>, Schema.Struct<{
87
+ readonly type: Schema.Literal<"media">;
88
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
89
+ readonly data: Schema.String;
90
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
91
+ readonly bytes: Schema.Int;
92
+ readonly name: Schema.optionalKey<Schema.String>;
93
+ readonly alt: Schema.optionalKey<Schema.String>;
94
+ }>]>>]>;
64
95
  readonly providerOptions: Schema.optional<Schema.Unknown>;
65
96
  }>, Schema.Struct<{
66
97
  readonly role: Schema.Literal<"assistant">;
@@ -90,6 +121,15 @@ export declare const LogBody: Schema.Union<readonly [Schema.TaggedStruct<"System
90
121
  readonly output: Schema.Unknown;
91
122
  readonly providerOptions: Schema.optional<Schema.Unknown>;
92
123
  readonly isError: Schema.optional<Schema.Boolean>;
124
+ readonly media: Schema.optionalKey<Schema.$Array<Schema.Struct<{
125
+ readonly type: Schema.Literal<"media">;
126
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
127
+ readonly data: Schema.String;
128
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
129
+ readonly bytes: Schema.Int;
130
+ readonly name: Schema.optionalKey<Schema.String>;
131
+ readonly alt: Schema.optionalKey<Schema.String>;
132
+ }>>>;
93
133
  }>>;
94
134
  readonly providerOptions: Schema.optional<Schema.Unknown>;
95
135
  }>]>;
@@ -117,6 +157,26 @@ export declare const LogBody: Schema.Union<readonly [Schema.TaggedStruct<"System
117
157
  }>>;
118
158
  /** Pinned results survive every compaction verbatim. */
119
159
  readonly pinned: Schema.Boolean;
160
+ /**
161
+ * The images the model is sent with the result, where they are in
162
+ * `encoded` (each stored once, there), checked when the result was
163
+ * written; only when there are some, so a result without images is
164
+ * stored as before.
165
+ */
166
+ readonly media: Schema.optionalKey<Schema.$Array<Schema.Struct<{
167
+ readonly path: Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Int]>>;
168
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
169
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
170
+ readonly bytes: Schema.Int;
171
+ }>>>;
172
+ /**
173
+ * The lines `view` ends with for the images the result does not send (an
174
+ * `[image unavailable: …]` line, or the label line of one past the
175
+ * per-result caps); only when there are some. A result shown through
176
+ * other text (a compaction's, a digest's, a spill's preview) shows them
177
+ * after that text.
178
+ */
179
+ readonly mediaNotes: Schema.optionalKey<Schema.$Array<Schema.String>>;
120
180
  }>, Schema.TaggedStruct<"ToolDigest", {
121
181
  readonly entry: Schema.brand<Schema.Trimmed, "EntryId">;
122
182
  readonly version: Schema.String;
@@ -148,6 +208,9 @@ export declare const LogBody: Schema.Union<readonly [Schema.TaggedStruct<"System
148
208
  }>, Schema.TaggedStruct<"Summarize", {
149
209
  readonly keepFromTurn: Schema.Int;
150
210
  readonly summary: Schema.String;
211
+ }>, Schema.TaggedStruct<"OmitMedia", {
212
+ readonly entries: Schema.$Array<Schema.brand<Schema.Trimmed, "EntryId">>;
213
+ readonly reason: Schema.String;
151
214
  }>]>;
152
215
  }>, Schema.TaggedStruct<"TurnEnded", {
153
216
  readonly outcome: Schema.Literals<readonly ["completed", "partial", "failed"]>;
@@ -168,18 +231,40 @@ export declare const LogEntry: Schema.Struct<{
168
231
  readonly version: Schema.String;
169
232
  readonly fingerprint: Schema.String;
170
233
  }>>;
171
- }>, Schema.encodeKeys<Schema.TaggedStruct<"TurnStarted", {
172
- readonly userMessage: Schema.decodeTo<typeof import("@xandreed/sdk").UserMessage, Schema.String, never, never>;
173
- }>, {
174
- readonly userMessage: "prompt";
175
- }>, Schema.TaggedStruct<"TurnContext", {
234
+ }>, Schema.decodeTo<Schema.TaggedStruct<"TurnStarted", {
235
+ readonly userMessage: typeof UserMessage;
236
+ }>, Schema.Struct<{
237
+ readonly _tag: Schema.Literal<"TurnStarted">;
238
+ readonly prompt: Schema.String;
239
+ readonly attachments: Schema.optionalKey<Schema.$Array<Schema.toEncoded<Schema.Struct<{
240
+ readonly type: Schema.Literal<"media">;
241
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
242
+ readonly data: Schema.String;
243
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
244
+ readonly bytes: Schema.Int;
245
+ readonly name: Schema.optionalKey<Schema.String>;
246
+ readonly alt: Schema.optionalKey<Schema.String>;
247
+ }>>>>;
248
+ }>, never, never>, Schema.TaggedStruct<"TurnContext", {
176
249
  readonly sectionId: Schema.String;
177
250
  readonly version: Schema.String;
178
251
  readonly text: Schema.String;
179
252
  }>, Schema.TaggedStruct<"Message", {
180
253
  readonly message: Schema.Union<readonly [Schema.Struct<{
181
254
  readonly role: Schema.Literal<"user">;
182
- readonly content: Schema.String;
255
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{
256
+ readonly type: Schema.Literal<"text">;
257
+ readonly text: Schema.String;
258
+ readonly providerOptions: Schema.optional<Schema.Unknown>;
259
+ }>, Schema.Struct<{
260
+ readonly type: Schema.Literal<"media">;
261
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
262
+ readonly data: Schema.String;
263
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
264
+ readonly bytes: Schema.Int;
265
+ readonly name: Schema.optionalKey<Schema.String>;
266
+ readonly alt: Schema.optionalKey<Schema.String>;
267
+ }>]>>]>;
183
268
  readonly providerOptions: Schema.optional<Schema.Unknown>;
184
269
  }>, Schema.Struct<{
185
270
  readonly role: Schema.Literal<"assistant">;
@@ -209,6 +294,15 @@ export declare const LogEntry: Schema.Struct<{
209
294
  readonly output: Schema.Unknown;
210
295
  readonly providerOptions: Schema.optional<Schema.Unknown>;
211
296
  readonly isError: Schema.optional<Schema.Boolean>;
297
+ readonly media: Schema.optionalKey<Schema.$Array<Schema.Struct<{
298
+ readonly type: Schema.Literal<"media">;
299
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
300
+ readonly data: Schema.String;
301
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
302
+ readonly bytes: Schema.Int;
303
+ readonly name: Schema.optionalKey<Schema.String>;
304
+ readonly alt: Schema.optionalKey<Schema.String>;
305
+ }>>>;
212
306
  }>>;
213
307
  readonly providerOptions: Schema.optional<Schema.Unknown>;
214
308
  }>]>;
@@ -236,6 +330,26 @@ export declare const LogEntry: Schema.Struct<{
236
330
  }>>;
237
331
  /** Pinned results survive every compaction verbatim. */
238
332
  readonly pinned: Schema.Boolean;
333
+ /**
334
+ * The images the model is sent with the result, where they are in
335
+ * `encoded` (each stored once, there), checked when the result was
336
+ * written; only when there are some, so a result without images is
337
+ * stored as before.
338
+ */
339
+ readonly media: Schema.optionalKey<Schema.$Array<Schema.Struct<{
340
+ readonly path: Schema.$Array<Schema.Union<readonly [Schema.String, Schema.Int]>>;
341
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
342
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
343
+ readonly bytes: Schema.Int;
344
+ }>>>;
345
+ /**
346
+ * The lines `view` ends with for the images the result does not send (an
347
+ * `[image unavailable: …]` line, or the label line of one past the
348
+ * per-result caps); only when there are some. A result shown through
349
+ * other text (a compaction's, a digest's, a spill's preview) shows them
350
+ * after that text.
351
+ */
352
+ readonly mediaNotes: Schema.optionalKey<Schema.$Array<Schema.String>>;
239
353
  }>, Schema.TaggedStruct<"ToolDigest", {
240
354
  readonly entry: Schema.brand<Schema.Trimmed, "EntryId">;
241
355
  readonly version: Schema.String;
@@ -267,6 +381,9 @@ export declare const LogEntry: Schema.Struct<{
267
381
  }>, Schema.TaggedStruct<"Summarize", {
268
382
  readonly keepFromTurn: Schema.Int;
269
383
  readonly summary: Schema.String;
384
+ }>, Schema.TaggedStruct<"OmitMedia", {
385
+ readonly entries: Schema.$Array<Schema.brand<Schema.Trimmed, "EntryId">>;
386
+ readonly reason: Schema.String;
270
387
  }>]>;
271
388
  }>, Schema.TaggedStruct<"TurnEnded", {
272
389
  readonly outcome: Schema.Literals<readonly ["completed", "partial", "failed"]>;
@@ -278,7 +395,19 @@ export type LogEntry = typeof LogEntry.Type;
278
395
  export declare const BuiltContext: Schema.Struct<{
279
396
  readonly messages: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
280
397
  readonly role: Schema.Literal<"user">;
281
- readonly content: Schema.String;
398
+ readonly content: Schema.Union<readonly [Schema.String, Schema.$Array<Schema.Union<readonly [Schema.Struct<{
399
+ readonly type: Schema.Literal<"text">;
400
+ readonly text: Schema.String;
401
+ readonly providerOptions: Schema.optional<Schema.Unknown>;
402
+ }>, Schema.Struct<{
403
+ readonly type: Schema.Literal<"media">;
404
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
405
+ readonly data: Schema.String;
406
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
407
+ readonly bytes: Schema.Int;
408
+ readonly name: Schema.optionalKey<Schema.String>;
409
+ readonly alt: Schema.optionalKey<Schema.String>;
410
+ }>]>>]>;
282
411
  readonly providerOptions: Schema.optional<Schema.Unknown>;
283
412
  }>, Schema.Struct<{
284
413
  readonly role: Schema.Literal<"assistant">;
@@ -308,6 +437,15 @@ export declare const BuiltContext: Schema.Struct<{
308
437
  readonly output: Schema.Unknown;
309
438
  readonly providerOptions: Schema.optional<Schema.Unknown>;
310
439
  readonly isError: Schema.optional<Schema.Boolean>;
440
+ readonly media: Schema.optionalKey<Schema.$Array<Schema.Struct<{
441
+ readonly type: Schema.Literal<"media">;
442
+ readonly mediaType: Schema.Literals<readonly ["image/png", "image/jpeg", "image/gif", "image/webp"]>;
443
+ readonly data: Schema.String;
444
+ readonly fingerprint: Schema.brand<Schema.String, "MediaFingerprint">;
445
+ readonly bytes: Schema.Int;
446
+ readonly name: Schema.optionalKey<Schema.String>;
447
+ readonly alt: Schema.optionalKey<Schema.String>;
448
+ }>>>;
311
449
  }>>;
312
450
  readonly providerOptions: Schema.optional<Schema.Unknown>;
313
451
  }>]>>;
@@ -7,6 +7,10 @@ export declare const canonicalJson: (value: unknown) => string;
7
7
  export declare const fingerprintOf: (text: string) => string;
8
8
  /** A deliberately conservative estimate for mixed prose and JSON. */
9
9
  export declare const estimateTokens: (text: string) => number;
10
+ /**
11
+ * The messages' tokens, estimated: each message's JSON as text, with an
12
+ * image counted as `IMAGE_TOKEN_ESTIMATE` tokens instead of its base64.
13
+ */
10
14
  export declare const estimateMessageTokens: (messages: ReadonlyArray<AgentMessage>) => number;
11
15
  export declare const entryId: (runId: string, index: number) => EntryId;
12
16
  export interface RenderOptions {
@@ -23,18 +27,40 @@ export interface RenderOptions {
23
27
  /** Show recorded tool digests in place of the results they digest. */
24
28
  readonly digests: boolean;
25
29
  /**
26
- * How artifacts reach the model. `none`: a reference line after the
27
- * result's text. `inline` is reserved for image parts; messages carry text
28
- * only today, so it renders like `none`.
30
+ * How images reach the model: a user's attachments and the images tool
31
+ * results return (each result's slots, while it shows the view it was
32
+ * written with). The current turn's are sent as images first: its
33
+ * attachments in order, then its tool results' images, newest result
34
+ * first and a whole result at a time, while they fit. `none` shows every
35
+ * earlier turn's image as a `mediaLabel` line; `inline` sends earlier
36
+ * turns' images too, newest turn first and a whole turn at a time, while
37
+ * they fit. Together they stay within `maxImages` images (and never more
38
+ * than `MEDIA_LIMITS.requestImages`) and `maxChars` base64 characters; an
39
+ * image left out is a label line. With the memory plugins' defaults a
40
+ * message's own images always fit; `maxChars: 0` sends none (text only).
41
+ * An `ArtifactRef` is a reference line after its result's text in both
42
+ * modes, at most `maxImages` of them.
29
43
  */
30
44
  readonly media: {
31
45
  readonly mode: "none" | "inline";
32
46
  readonly maxImages: number;
47
+ readonly maxChars: number;
33
48
  };
34
49
  }
35
50
  /** The reference lines a result's artifacts add to its text. */
36
51
  export declare const artifactLines: (artifacts: ReadonlyArray<ArtifactRef>, maxImages: number) => string;
37
52
  export declare const renderLog: (entries: ReadonlyArray<LogEntry>, options: RenderOptions) => ReadonlyArray<AgentMessage>;
53
+ /**
54
+ * The entries whose images a render sends as images (a user's attachments,
55
+ * a tool result's): what an `OmitMedia` compaction names after a provider
56
+ * refused that request. Empty when the render sends no image.
57
+ */
58
+ export declare const entriesSendingMedia: (entries: ReadonlyArray<LogEntry>, options: RenderOptions) => ReadonlyArray<EntryId>;
59
+ /**
60
+ * The rebuild of one request, with its fingerprint: the hash of the
61
+ * messages' canonical JSON, each image's `data` replaced by its fingerprint
62
+ * (`elideMediaData`), so a text-only context hashes as it always did.
63
+ */
38
64
  export declare const buildContext: (entries: ReadonlyArray<LogEntry>, options: RenderOptions) => BuiltContext;
39
65
  /** The latest step context recorded by this run, if any. */
40
66
  export declare const stepContextOf: (entries: ReadonlyArray<LogEntry>, runId: string) => Option.Option<string>;
@@ -47,9 +73,13 @@ export declare const activationsOf: (entries: ReadonlyArray<LogEntry>) => {
47
73
  readonly skills: ReadonlyArray<string>;
48
74
  readonly tools: ReadonlyArray<string>;
49
75
  };
50
- /** A compact user/assistant transcript for classifiers: user messages and replies only. */
76
+ /** A compact user/assistant transcript for classifiers: user messages (an image as its label line) and replies only. */
51
77
  export declare const referenceTranscript: (entries: ReadonlyArray<LogEntry>) => ReadonlyArray<AgentMessage>;
52
- /** The full-fidelity transcript: messages with every tool result's encoded value. */
78
+ /**
79
+ * The full-fidelity transcript: messages with every tool result's encoded
80
+ * value. Images are left out: a user's image is its label line, an image in
81
+ * an encoded value has its `data` replaced by its fingerprint.
82
+ */
53
83
  export declare const rawTranscript: (entries: ReadonlyArray<LogEntry>) => ReadonlyArray<AgentMessage>;
54
84
  export interface LogQuery {
55
85
  readonly kinds: ReadonlyArray<LogBody["_tag"]>;