@theokit/sdk 2.3.0 → 2.5.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 (101) hide show
  1. package/CHANGELOG.md +113 -0
  2. package/dist/a2a/index.cjs +103 -48
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +104 -49
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/compaction.cjs +78 -0
  7. package/dist/compaction.cjs.map +1 -0
  8. package/dist/compaction.d.cts +76 -0
  9. package/dist/compaction.d.ts +76 -0
  10. package/dist/compaction.js +70 -0
  11. package/dist/compaction.js.map +1 -0
  12. package/dist/{cron-B_H8rn-j.d.cts → cron-B656C3iq.d.cts} +8 -0
  13. package/dist/{cron-DX6HbHxd.d.ts → cron-CM2M9mhB.d.ts} +8 -0
  14. package/dist/cron.cjs +104 -57
  15. package/dist/cron.cjs.map +1 -1
  16. package/dist/cron.d.cts +1 -1
  17. package/dist/cron.d.ts +1 -1
  18. package/dist/cron.js +104 -57
  19. package/dist/cron.js.map +1 -1
  20. package/dist/eval.cjs +296 -73
  21. package/dist/eval.cjs.map +1 -1
  22. package/dist/eval.d.cts +2 -0
  23. package/dist/eval.d.ts +2 -0
  24. package/dist/eval.js +295 -75
  25. package/dist/eval.js.map +1 -1
  26. package/dist/index.cjs +135 -65
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +42 -7
  29. package/dist/index.d.ts +42 -7
  30. package/dist/index.js +135 -66
  31. package/dist/index.js.map +1 -1
  32. package/dist/internal/agent-loop/loop.d.ts +5 -0
  33. package/dist/internal/eval/code-runner.d.ts +28 -0
  34. package/dist/internal/llm/model-capabilities.d.ts +40 -0
  35. package/dist/internal/llm/model-identifier.d.ts +9 -1
  36. package/dist/internal/llm/model-option.d.ts +38 -0
  37. package/dist/internal/persistence/index.cjs +68 -0
  38. package/dist/internal/persistence/index.cjs.map +1 -1
  39. package/dist/internal/persistence/index.d.cts +1 -0
  40. package/dist/internal/persistence/index.d.ts +1 -0
  41. package/dist/internal/persistence/index.js +65 -1
  42. package/dist/internal/persistence/index.js.map +1 -1
  43. package/dist/internal/persistence/jsonl.d.cts +34 -0
  44. package/dist/internal/persistence/jsonl.d.ts +34 -0
  45. package/dist/internal/runtime/compression/compression-attempt.d.ts +24 -0
  46. package/dist/internal/runtime/compression/compression-config.d.ts +33 -0
  47. package/dist/internal/runtime/compression/compression-decision.d.ts +10 -0
  48. package/dist/internal/runtime/compression/compression-helpers.d.ts +18 -0
  49. package/dist/internal/runtime/compression/compression-model-registry.d.ts +41 -0
  50. package/dist/internal/runtime/compression/compression-summarizer.d.ts +29 -0
  51. package/dist/internal/runtime/context/project-instructions.d.ts +66 -0
  52. package/dist/internal/runtime/context/replay-history.d.ts +43 -0
  53. package/dist/internal/runtime/hooks/hooks-frontmatter.d.ts +1 -1
  54. package/dist/internal/runtime/skills/discover-skills.d.ts +68 -0
  55. package/dist/internal/runtime/skills/skills-block.d.ts +18 -0
  56. package/dist/internal/runtime/skills/subagent-tool-scope.d.ts +25 -0
  57. package/dist/messages.cjs +24 -0
  58. package/dist/messages.cjs.map +1 -0
  59. package/dist/messages.d.cts +33 -0
  60. package/dist/messages.d.ts +33 -0
  61. package/dist/messages.js +20 -0
  62. package/dist/messages.js.map +1 -0
  63. package/dist/models.cjs +233 -0
  64. package/dist/models.cjs.map +1 -0
  65. package/dist/models.d.cts +16 -0
  66. package/dist/models.d.ts +16 -0
  67. package/dist/models.js +228 -0
  68. package/dist/models.js.map +1 -0
  69. package/dist/permission-engine.d.ts +12 -4
  70. package/dist/project.cjs +149 -0
  71. package/dist/project.cjs.map +1 -0
  72. package/dist/project.d.cts +14 -0
  73. package/dist/project.d.ts +14 -0
  74. package/dist/project.js +146 -0
  75. package/dist/project.js.map +1 -0
  76. package/dist/sandbox/index.cjs +71 -1
  77. package/dist/sandbox/index.cjs.map +1 -1
  78. package/dist/sandbox/index.d.cts +1 -0
  79. package/dist/sandbox/index.d.ts +1 -0
  80. package/dist/sandbox/index.js +70 -2
  81. package/dist/sandbox/index.js.map +1 -1
  82. package/dist/sandbox/provision.d.cts +53 -0
  83. package/dist/sandbox/provision.d.ts +53 -0
  84. package/dist/sandbox/shell-escape.d.cts +8 -0
  85. package/dist/sandbox/shell-escape.d.ts +8 -0
  86. package/dist/scorers.d.ts +19 -1
  87. package/dist/skills.cjs +282 -0
  88. package/dist/skills.cjs.map +1 -0
  89. package/dist/skills.d.cts +19 -0
  90. package/dist/skills.d.ts +19 -0
  91. package/dist/skills.js +279 -0
  92. package/dist/skills.js.map +1 -0
  93. package/dist/subagents.cjs +24 -0
  94. package/dist/subagents.cjs.map +1 -0
  95. package/dist/subagents.d.cts +14 -0
  96. package/dist/subagents.d.ts +14 -0
  97. package/dist/subagents.js +21 -0
  98. package/dist/subagents.js.map +1 -0
  99. package/dist/types/agent.d.ts +8 -0
  100. package/dist/types/eval.d.ts +71 -0
  101. package/package.json +74 -14
@@ -0,0 +1,10 @@
1
+ /**
2
+ * T2.2 step 4a/N — Compression decision logic (ADR D440).
3
+ *
4
+ * Pure function that determines whether the agent-loop should attempt
5
+ * context-window compression on a given error. Isolates the decision
6
+ * matrix from the loop.ts hot path so it's independently testable.
7
+ *
8
+ * @internal
9
+ */
10
+ export {};
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Compression helpers (T2.3, ADR D92).
3
+ *
4
+ * Scaffold for future compression LLM integration:
5
+ * - `selectCompressionWindow` — splits messages into compress/preserve halves
6
+ * - `assertCompressionReduced` — 10% reduction floor to detect "compression placebo"
7
+ *
8
+ * The compression LLM call itself is out of scope for this plan (requires
9
+ * an auxiliary-model ADR). These helpers are used by `Agent.send` when a
10
+ * future iteration adds compression.
11
+ *
12
+ * @internal
13
+ */
14
+ export interface CompressionCheck {
15
+ reduced: boolean;
16
+ reductionPct: number;
17
+ reason?: string;
18
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * T2.2 — Provider-agnostic compression-model registry (ADR D440).
3
+ *
4
+ * Resolves a cheaper-tier summarization model in the SAME vendor family
5
+ * as the agent's main model. Provider-agnostic by design: a consumer
6
+ * running on Anthropic-only / Ollama-only / Bedrock-only never needs
7
+ * to provision a second vendor's key for the compression aux-LLM.
8
+ *
9
+ * Resolution algorithm:
10
+ *
11
+ * 1. Exact match in `EXACT_REGISTRY` → cheaper-tier id (most cases).
12
+ * 2. Wildcard match in `WILDCARD_REGISTRY` (`*` suffix in key) →
13
+ * swap matched suffix (Bedrock region-prefixed variants).
14
+ * 3. Provider in `NO_AUTH_PROVIDERS` (Ollama / LM Studio / llama.cpp)
15
+ * → return SAME model id (local — cost N/A; running the same
16
+ * model for summarization costs only the round-trip latency,
17
+ * acceptable in dev/local mode).
18
+ * 4. No match → throw `CompressionModelUnresolvedError` with the
19
+ * actionable message naming the model + override path + the
20
+ * registry-PR remediation hint.
21
+ *
22
+ * Step 1 of T2.2 (compression-helpers wire). Step 2 wires this into
23
+ * `compression-config.ts`. Step 3 builds the OTel-instrumented aux
24
+ * client. Step 4 wires into `loop.ts` ContextWindowExceededError catch.
25
+ *
26
+ * @internal
27
+ */
28
+ /**
29
+ * T2.2 — Typed error thrown when `resolveCompressionModel` cannot
30
+ * find a same-family-cheaper-tier mapping for `agentModel`. Surfaces
31
+ * the offending model id so operators can either (a) provide
32
+ * `Agent.create({compression: {model: ...}})` explicitly or (b) open
33
+ * a registry-PR adding the missing entry.
34
+ *
35
+ * @public
36
+ */
37
+ export declare class CompressionModelUnresolvedError extends Error {
38
+ readonly name = "CompressionModelUnresolvedError";
39
+ readonly agentModel: string;
40
+ constructor(agentModel: string);
41
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * T2.2 step 3/N — Compression summarizer (ADR D440).
3
+ *
4
+ * Takes a conversation window (messages to compress) + a resolved
5
+ * compression model + an injected LLM caller, and returns a single
6
+ * system-role summary message that replaces the compressed window.
7
+ *
8
+ * The `callLlm` parameter is dependency-injected so:
9
+ * - Unit tests pass a deterministic fake (no real-LLM cost)
10
+ * - The agent-loop passes a real LLM client bound to the resolved
11
+ * compression config (step 4 wire)
12
+ *
13
+ * Failure mode per ADR D440: if the LLM call fails, throws
14
+ * `CompressionFailedError` — the caller (loop.ts) catches this,
15
+ * logs WARN with redacted metadata, and returns the ORIGINAL
16
+ * conversation unchanged (counter incremented toward cap 3).
17
+ *
18
+ * @internal
19
+ */
20
+ /**
21
+ * Typed error thrown when the compression LLM call fails or returns
22
+ * an empty/ineffective summary. The caller catches and handles per
23
+ * ADR D440 failure mode (WARN + original conversation + counter).
24
+ *
25
+ * @public
26
+ */
27
+ export declare class CompressionFailedError extends Error {
28
+ readonly name = "CompressionFailedError";
29
+ }
@@ -0,0 +1,66 @@
1
+ /** How discovered instruction files are reduced to a single `content` string. */
2
+ export type ProjectInstructionScope = "nearest" | "merged";
3
+ /** One discovered project-instruction file. */
4
+ export interface ProjectInstructionFile {
5
+ /** Absolute path to the file. */
6
+ path: string;
7
+ /** Full file content (never truncated — the caller bounds it). */
8
+ content: string;
9
+ }
10
+ /** Result of {@link readProjectInstructions}. */
11
+ export interface ProjectInstructions {
12
+ /** Found files, nearest-first (innermost directory first). Empty if none. */
13
+ files: ProjectInstructionFile[];
14
+ /**
15
+ * The `scope`-selected reduction: `nearest` → the innermost file's content;
16
+ * `merged` → all files joined root-first (nearest content last). `undefined`
17
+ * when no file was found.
18
+ */
19
+ content: string | undefined;
20
+ }
21
+ /** Options for {@link readProjectInstructions}. */
22
+ export interface ReadProjectInstructionsOptions {
23
+ /** Instruction filename to discover. Default `"THEO.md"`. */
24
+ filename?: string;
25
+ /** How to reduce the found files to `content`. Default `"nearest"`. */
26
+ scope?: ProjectInstructionScope;
27
+ /** Stop the upward walk at this directory (inclusive). Default: filesystem root. */
28
+ stopDir?: string;
29
+ }
30
+ /** Options for {@link writeProjectInstructions}. */
31
+ export interface WriteProjectInstructionsOptions {
32
+ /** Instruction filename to write. Default `"THEO.md"`. */
33
+ filename?: string;
34
+ }
35
+ /**
36
+ * Read hierarchical project instructions by walking up from `cwd`.
37
+ *
38
+ * Discovers every `<dir>/<filename>` from `cwd` up to the filesystem root (or
39
+ * `stopDir`), reads each, and returns them nearest-first in `files` plus a
40
+ * `content` reduction chosen by `scope`. Composes the hardened internal
41
+ * `walkUpForFile` (64-level cap, realpath dedup, FS-race tolerant).
42
+ *
43
+ * NEVER throws: a missing/unreadable directory or a path that exists but is not
44
+ * a readable file is skipped; no instruction file → `{ files: [], content: undefined }`.
45
+ *
46
+ * Public via `@theokit/sdk/project`.
47
+ *
48
+ * @public
49
+ */
50
+ export declare function readProjectInstructions(cwd: string, options?: ReadProjectInstructionsOptions): Promise<ProjectInstructions>;
51
+ /**
52
+ * Write project instructions to `<cwd>/<filename>` atomically (temp + fsync +
53
+ * rename, via the shipped `replaceFileAtomic`).
54
+ *
55
+ * Unlike the reader, this FAILS LOUD: an unsafe `filename` (path traversal,
56
+ * separators, absolute) is rejected with `ConfigurationError`
57
+ * (`code: "unsafe_filename"`) — symmetric with the reader, whose `filename`
58
+ * flows through the same `isSafePattern` guard — and a write error (e.g. the
59
+ * parent directory does not exist) propagates to the caller. A failed mutation
60
+ * is a real error, never silently swallowed.
61
+ *
62
+ * Public via `@theokit/sdk/project`.
63
+ *
64
+ * @public
65
+ */
66
+ export declare function writeProjectInstructions(cwd: string, content: string, options?: WriteProjectInstructionsOptions): Promise<void>;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Stateless continuation-history rebuild (M1-3 — plan m1-continuation-history).
3
+ *
4
+ * `buildReplayHistory` serializes `SDKMessage[]` stream events into a bounded
5
+ * `StoredMessage[]` replay history for the STATELESS continuation path: a server
6
+ * (or serverless handler) that re-runs an agent on a fresh request reconstructs
7
+ * the working memory from persisted events rather than a live session. The
8
+ * replayed history is the ONLY working memory the continued model has, so it
9
+ * MUST carry tool-result content and be bounded against the context window.
10
+ *
11
+ * Complements M1 Phase 3 `runToCompletion` (the STATEFUL path, where the session
12
+ * preserves history). Pure, sync, dependency-free; reuses the SDK's own
13
+ * `truncateWithMarker` for per-item caps (Rule 9). Design: blueprint
14
+ * `m1-continuation-history` ADRs D1-D5; first-party baseline
15
+ * `theocode/server/lib/continuation-history.ts`.
16
+ *
17
+ * @public
18
+ */
19
+ import type { StoredMessage } from "../../../types/conversation-storage.js";
20
+ import type { SDKMessage } from "../../../types/messages.js";
21
+ /**
22
+ * Options for {@link buildReplayHistory}.
23
+ *
24
+ * @public
25
+ */
26
+ export interface ReplayHistoryOptions {
27
+ /** The continued model's context window, in tokens. Drives the char budget. */
28
+ contextWindowTokens: number;
29
+ /** Tokens held back for system + continuation prompt + reply. Default 8000. */
30
+ reserveTokens?: number;
31
+ /**
32
+ * Max characters for a single oversized turn before it is truncated (never
33
+ * dropped). Default `floor(budgetChars / 2)`. Guarded to ≥ 0.
34
+ */
35
+ perItemCap?: number;
36
+ }
37
+ /**
38
+ * Rebuild a bounded replay history from `base` (prior durable turns) plus the
39
+ * `events` of the latest round. Returns a NEW array; never mutates inputs.
40
+ *
41
+ * @public
42
+ */
43
+ export declare function buildReplayHistory(base: readonly StoredMessage[], events: readonly SDKMessage[], options: ReplayHistoryOptions): StoredMessage[];
@@ -11,11 +11,11 @@
11
11
  export declare const HOOK_EVENTS: readonly ["preRun", "postRun", "preToolUse", "postToolUse", "stop"];
12
12
  export declare const HookFrontmatterSchema: z.ZodObject<{
13
13
  event: z.ZodEnum<{
14
- stop: "stop";
15
14
  preRun: "preRun";
16
15
  postRun: "postRun";
17
16
  preToolUse: "preToolUse";
18
17
  postToolUse: "postToolUse";
18
+ stop: "stop";
19
19
  }>;
20
20
  matcher: z.ZodString;
21
21
  command: z.ZodString;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * A discovered skill's metadata. The skill BODY is never included — only the
3
+ * strict frontmatter fields plus the resolved `source` path.
4
+ *
5
+ * Public via `@theokit/sdk/skills`.
6
+ *
7
+ * @public
8
+ */
9
+ export interface Skill {
10
+ name: string;
11
+ description: string;
12
+ /** Absolute path to the discovered `SKILL.md`. */
13
+ source: string;
14
+ category?: string;
15
+ dependencies?: string[];
16
+ }
17
+ /**
18
+ * Information passed to `onInvalidSkill` when a `SKILL.md` is present but its
19
+ * frontmatter is malformed (missing required field or invalid YAML).
20
+ *
21
+ * @public
22
+ */
23
+ export interface InvalidSkillInfo {
24
+ /** The skill directory name (used as the fallback skill name). */
25
+ name: string;
26
+ /** Absolute path to the offending `SKILL.md`. */
27
+ source: string;
28
+ /** Typed reason: `missing_frontmatter` or `schema_invalid`. */
29
+ code: string;
30
+ message: string;
31
+ }
32
+ /**
33
+ * Options for {@link discoverSkills}.
34
+ *
35
+ * @public
36
+ */
37
+ export interface DiscoverSkillsOptions {
38
+ /**
39
+ * Called once per directory that contains a `SKILL.md` with malformed
40
+ * frontmatter. The skill is excluded from the result; discovery continues
41
+ * (strict-frontmatter ADR / EC-5). A directory WITHOUT a `SKILL.md` is NOT a
42
+ * malformed skill and does not trigger this callback.
43
+ *
44
+ * Default: no-op (a library primitive must not write to the consumer's
45
+ * stderr by default).
46
+ */
47
+ onInvalidSkill?: (info: InvalidSkillInfo) => void;
48
+ }
49
+ /**
50
+ * Discover `SKILL.md` skills under an arbitrary directory.
51
+ *
52
+ * For each immediate subdirectory `<dir>/<name>/` containing a `SKILL.md`, the
53
+ * file's strict YAML frontmatter is parsed (`name`/`description` required;
54
+ * `category`/`dependencies` optional). Malformed skills are skipped (optionally
55
+ * reported via {@link DiscoverSkillsOptions.onInvalidSkill}); a subdirectory
56
+ * whose realpath escapes `dir` (via symlink) is skipped (symlink-escape guard,
57
+ * reusing `@theokit/sdk/path-safety`).
58
+ *
59
+ * NEVER throws: a missing, unreadable, or non-directory `dir` yields `[]`.
60
+ *
61
+ * Discovery order follows the filesystem `readdir` order (OS-dependent). Sort
62
+ * the result before {@link buildSkillsBlock} if a stable block order matters.
63
+ *
64
+ * Public via `@theokit/sdk/skills`.
65
+ *
66
+ * @public
67
+ */
68
+ export declare function discoverSkills(dir: string, options?: DiscoverSkillsOptions): Promise<Skill[]>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Render the `<skills>` system-prompt block from a skill list.
3
+ *
4
+ * Input is the structural subset `{ name, description }` — the skill BODY is
5
+ * NOT in the type, so it cannot leak into the prompt. Both fields are passed
6
+ * through `escapeBlockBody` to neutralise prompt-injection vectors hidden in
7
+ * user-controlled SKILL.md frontmatter (injection-escape ADR).
8
+ *
9
+ * Returns `undefined` for an empty list so the caller can omit the block.
10
+ *
11
+ * Public via `@theokit/sdk/skills`.
12
+ *
13
+ * @public
14
+ */
15
+ export declare function buildSkillsBlock(skills: ReadonlyArray<{
16
+ name: string;
17
+ description: string;
18
+ }>): string | undefined;
@@ -0,0 +1,25 @@
1
+ import type { AgentDefinition } from "../../../types/agent.js";
2
+ /**
3
+ * Resolve a sub-agent's tool whitelist from its {@link AgentDefinition.tools}
4
+ * (M4-6). Returns a `Set` of allowed tool names when `tools` is a non-empty
5
+ * array, else `undefined` (unscoped — the sub-agent inherits the parent's full
6
+ * toolset). The `Set` is the exact shape `withToolWhitelist` /
7
+ * `ForkOptions.allowedTools` consume.
8
+ *
9
+ * @public
10
+ */
11
+ export declare function subagentToolWhitelist(definition: AgentDefinition): Set<string> | undefined;
12
+ /**
13
+ * Run `fn` under the sub-agent's tool whitelist (M4-6). When the definition
14
+ * declares `tools`, the run executes inside `withToolWhitelist(set, fn)` — so
15
+ * every tool call the sub-agent makes is vetoed at dispatch (`checkToolWhitelist`,
16
+ * the same enforcement forks use) unless its canonical name is whitelisted: a
17
+ * `tools: ["read_file"]` sub-agent provably cannot call `write_file`/`shell_exec`.
18
+ * Enforcement is `withToolWhitelist`, NOT `PermissionEngine`.
19
+ *
20
+ * An unscoped definition (no/empty `tools`) runs `fn` directly — the parent's
21
+ * full toolset is preserved.
22
+ *
23
+ * @public
24
+ */
25
+ export declare function withSubagentToolScope<T>(definition: AgentDefinition, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ // src/messages.ts
4
+ function assistantText(msg) {
5
+ if (msg.type !== "assistant") {
6
+ return "";
7
+ }
8
+ return msg.message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
9
+ }
10
+ function extractToolUses(msg) {
11
+ if (msg.type !== "assistant") {
12
+ return [];
13
+ }
14
+ return msg.message.content.filter((block) => block.type === "tool_use");
15
+ }
16
+ function costAmountUsd(cost) {
17
+ return cost?.amountUsd;
18
+ }
19
+
20
+ exports.assistantText = assistantText;
21
+ exports.costAmountUsd = costAmountUsd;
22
+ exports.extractToolUses = extractToolUses;
23
+ //# sourceMappingURL=messages.cjs.map
24
+ //# sourceMappingURL=messages.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts"],"names":[],"mappings":";;;AAmBO,SAAS,cAAc,GAAA,EAAyB;AACrD,EAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAI,OAAA,CAAQ,OAAA,CAChB,MAAA,CAAO,CAAC,UAA4D,KAAA,CAAM,IAAA,KAAS,MAAM,CAAA,CACzF,IAAI,CAAC,KAAA,KAAU,MAAM,IAAI,CAAA,CACzB,KAAK,EAAE,CAAA;AACZ;AASO,SAAS,gBAAgB,GAAA,EAAiC;AAC/D,EAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,GAAA,CAAI,QAAQ,OAAA,CAAQ,MAAA,CAAO,CAAC,KAAA,KAAiC,KAAA,CAAM,SAAS,UAAU,CAAA;AAC/F;AAQO,SAAS,cAAc,IAAA,EAAqD;AACjF,EAAA,OAAO,IAAA,EAAM,SAAA;AACf","file":"messages.cjs","sourcesContent":["/**\n * Pure readers over the `SDKMessage` stream (M1-5).\n *\n * Promotes the proven first-party hand-roll (`../theocode/server/lib/sdk-mappers.ts`)\n * onto the SDK's own types so consumers stop re-implementing a wire-event mapper.\n * Every reader is pure: no I/O, no mutation of its input, deterministic.\n *\n * Public from the `@theokit/sdk/messages` sub-path. See `docs.md → Message readers`.\n */\n\nimport type { SDKMessage, ToolUseBlock } from \"./types/messages.js\";\nimport type { CostBreakdown } from \"./types/usage.js\";\n\n/**\n * Concatenate the text of an assistant message's `TextBlock`s.\n *\n * Returns `\"\"` for any non-assistant message (or an assistant with no text\n * blocks). `tool_use` blocks are ignored — only `text` blocks contribute.\n */\nexport function assistantText(msg: SDKMessage): string {\n if (msg.type !== \"assistant\") {\n return \"\";\n }\n return msg.message.content\n .filter((block): block is Extract<typeof block, { type: \"text\" }> => block.type === \"text\")\n .map((block) => block.text)\n .join(\"\");\n}\n\n/**\n * Extract the `ToolUseBlock`s from an assistant message's content.\n *\n * Returns `[]` for any non-assistant message. This reads the assistant\n * message's content blocks — NOT the separate `SDKToolUseMessage`\n * (`type:\"tool_call\"`) lifecycle event, which is a different stream (ADR D2).\n */\nexport function extractToolUses(msg: SDKMessage): ToolUseBlock[] {\n if (msg.type !== \"assistant\") {\n return [];\n }\n return msg.message.content.filter((block): block is ToolUseBlock => block.type === \"tool_use\");\n}\n\n/**\n * Read the cost amount from a `CostBreakdown`, preserving the honesty contract\n * (repo ADR `D377-cost-status-closed-enum.md`): `amountUsd` is `number | undefined`\n * where `undefined` means \"cost unknown\" — distinct from a real `$0` (e.g. a\n * subscription-included route). NEVER coerced to 0.\n */\nexport function costAmountUsd(cost: CostBreakdown | undefined): number | undefined {\n return cost?.amountUsd;\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pure readers over the `SDKMessage` stream (M1-5).
3
+ *
4
+ * Promotes the proven first-party hand-roll (`../theocode/server/lib/sdk-mappers.ts`)
5
+ * onto the SDK's own types so consumers stop re-implementing a wire-event mapper.
6
+ * Every reader is pure: no I/O, no mutation of its input, deterministic.
7
+ *
8
+ * Public from the `@theokit/sdk/messages` sub-path. See `docs.md → Message readers`.
9
+ */
10
+ import type { SDKMessage, ToolUseBlock } from "./types/messages.js";
11
+ import type { CostBreakdown } from "./types/usage.js";
12
+ /**
13
+ * Concatenate the text of an assistant message's `TextBlock`s.
14
+ *
15
+ * Returns `""` for any non-assistant message (or an assistant with no text
16
+ * blocks). `tool_use` blocks are ignored — only `text` blocks contribute.
17
+ */
18
+ export declare function assistantText(msg: SDKMessage): string;
19
+ /**
20
+ * Extract the `ToolUseBlock`s from an assistant message's content.
21
+ *
22
+ * Returns `[]` for any non-assistant message. This reads the assistant
23
+ * message's content blocks — NOT the separate `SDKToolUseMessage`
24
+ * (`type:"tool_call"`) lifecycle event, which is a different stream (ADR D2).
25
+ */
26
+ export declare function extractToolUses(msg: SDKMessage): ToolUseBlock[];
27
+ /**
28
+ * Read the cost amount from a `CostBreakdown`, preserving the honesty contract
29
+ * (repo ADR `D377-cost-status-closed-enum.md`): `amountUsd` is `number | undefined`
30
+ * where `undefined` means "cost unknown" — distinct from a real `$0` (e.g. a
31
+ * subscription-included route). NEVER coerced to 0.
32
+ */
33
+ export declare function costAmountUsd(cost: CostBreakdown | undefined): number | undefined;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pure readers over the `SDKMessage` stream (M1-5).
3
+ *
4
+ * Promotes the proven first-party hand-roll (`../theocode/server/lib/sdk-mappers.ts`)
5
+ * onto the SDK's own types so consumers stop re-implementing a wire-event mapper.
6
+ * Every reader is pure: no I/O, no mutation of its input, deterministic.
7
+ *
8
+ * Public from the `@theokit/sdk/messages` sub-path. See `docs.md → Message readers`.
9
+ */
10
+ import type { SDKMessage, ToolUseBlock } from "./types/messages.js";
11
+ import type { CostBreakdown } from "./types/usage.js";
12
+ /**
13
+ * Concatenate the text of an assistant message's `TextBlock`s.
14
+ *
15
+ * Returns `""` for any non-assistant message (or an assistant with no text
16
+ * blocks). `tool_use` blocks are ignored — only `text` blocks contribute.
17
+ */
18
+ export declare function assistantText(msg: SDKMessage): string;
19
+ /**
20
+ * Extract the `ToolUseBlock`s from an assistant message's content.
21
+ *
22
+ * Returns `[]` for any non-assistant message. This reads the assistant
23
+ * message's content blocks — NOT the separate `SDKToolUseMessage`
24
+ * (`type:"tool_call"`) lifecycle event, which is a different stream (ADR D2).
25
+ */
26
+ export declare function extractToolUses(msg: SDKMessage): ToolUseBlock[];
27
+ /**
28
+ * Read the cost amount from a `CostBreakdown`, preserving the honesty contract
29
+ * (repo ADR `D377-cost-status-closed-enum.md`): `amountUsd` is `number | undefined`
30
+ * where `undefined` means "cost unknown" — distinct from a real `$0` (e.g. a
31
+ * subscription-included route). NEVER coerced to 0.
32
+ */
33
+ export declare function costAmountUsd(cost: CostBreakdown | undefined): number | undefined;
@@ -0,0 +1,20 @@
1
+ // src/messages.ts
2
+ function assistantText(msg) {
3
+ if (msg.type !== "assistant") {
4
+ return "";
5
+ }
6
+ return msg.message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
7
+ }
8
+ function extractToolUses(msg) {
9
+ if (msg.type !== "assistant") {
10
+ return [];
11
+ }
12
+ return msg.message.content.filter((block) => block.type === "tool_use");
13
+ }
14
+ function costAmountUsd(cost) {
15
+ return cost?.amountUsd;
16
+ }
17
+
18
+ export { assistantText, costAmountUsd, extractToolUses };
19
+ //# sourceMappingURL=messages.js.map
20
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/messages.ts"],"names":[],"mappings":";AAmBO,SAAS,cAAc,GAAA,EAAyB;AACrD,EAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,IAAA,OAAO,EAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAI,OAAA,CAAQ,OAAA,CAChB,MAAA,CAAO,CAAC,UAA4D,KAAA,CAAM,IAAA,KAAS,MAAM,CAAA,CACzF,IAAI,CAAC,KAAA,KAAU,MAAM,IAAI,CAAA,CACzB,KAAK,EAAE,CAAA;AACZ;AASO,SAAS,gBAAgB,GAAA,EAAiC;AAC/D,EAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,GAAA,CAAI,QAAQ,OAAA,CAAQ,MAAA,CAAO,CAAC,KAAA,KAAiC,KAAA,CAAM,SAAS,UAAU,CAAA;AAC/F;AAQO,SAAS,cAAc,IAAA,EAAqD;AACjF,EAAA,OAAO,IAAA,EAAM,SAAA;AACf","file":"messages.js","sourcesContent":["/**\n * Pure readers over the `SDKMessage` stream (M1-5).\n *\n * Promotes the proven first-party hand-roll (`../theocode/server/lib/sdk-mappers.ts`)\n * onto the SDK's own types so consumers stop re-implementing a wire-event mapper.\n * Every reader is pure: no I/O, no mutation of its input, deterministic.\n *\n * Public from the `@theokit/sdk/messages` sub-path. See `docs.md → Message readers`.\n */\n\nimport type { SDKMessage, ToolUseBlock } from \"./types/messages.js\";\nimport type { CostBreakdown } from \"./types/usage.js\";\n\n/**\n * Concatenate the text of an assistant message's `TextBlock`s.\n *\n * Returns `\"\"` for any non-assistant message (or an assistant with no text\n * blocks). `tool_use` blocks are ignored — only `text` blocks contribute.\n */\nexport function assistantText(msg: SDKMessage): string {\n if (msg.type !== \"assistant\") {\n return \"\";\n }\n return msg.message.content\n .filter((block): block is Extract<typeof block, { type: \"text\" }> => block.type === \"text\")\n .map((block) => block.text)\n .join(\"\");\n}\n\n/**\n * Extract the `ToolUseBlock`s from an assistant message's content.\n *\n * Returns `[]` for any non-assistant message. This reads the assistant\n * message's content blocks — NOT the separate `SDKToolUseMessage`\n * (`type:\"tool_call\"`) lifecycle event, which is a different stream (ADR D2).\n */\nexport function extractToolUses(msg: SDKMessage): ToolUseBlock[] {\n if (msg.type !== \"assistant\") {\n return [];\n }\n return msg.message.content.filter((block): block is ToolUseBlock => block.type === \"tool_use\");\n}\n\n/**\n * Read the cost amount from a `CostBreakdown`, preserving the honesty contract\n * (repo ADR `D377-cost-status-closed-enum.md`): `amountUsd` is `number | undefined`\n * where `undefined` means \"cost unknown\" — distinct from a real `$0` (e.g. a\n * subscription-included route). NEVER coerced to 0.\n */\nexport function costAmountUsd(cost: CostBreakdown | undefined): number | undefined {\n return cost?.amountUsd;\n}\n"]}