@princetheprogrammerbtw/husk 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,13 +3,16 @@
3
3
  > The agent harness that gives your LLM memory, hands, and a nervous system.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/%40princetheprogrammerbtw%2Fhusk.svg)](https://www.npmjs.com/package/@princetheprogrammerbtw/husk)
6
+ [![npm downloads](https://img.shields.io/npm/dm/%40princetheprogrammerbtw%2Fhusk.svg)](https://www.npmjs.com/package/@princetheprogrammerbtw/husk)
6
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
8
  [![Node](https://img.shields.io/node/v/%40princetheprogrammerbtw%2Fhusk.svg)](https://nodejs.org)
8
- [![CI](https://github.com/10xdev4u-alt/husk/actions/workflows/ci.yml/badge.svg)](./.github/workflows/ci.yml)
9
+ [![CI](https://github.com/10xdev4u-alt/husk/actions/workflows/ci.yml/badge.svg)](https://github.com/10xdev4u-alt/husk/actions/workflows/ci.yml)
10
+ [![GitHub stars](https://img.shields.io/github/stars/10xdev4u-alt/husk.svg)](https://github.com/10xdev4u-alt/husk/stargazers)
11
+ [![Bundle size](https://img.shields.io/bundlephobia/minzip/%40princetheprogrammerbtw%2Fhusk.svg)](https://bundlephobia.com/package/@princetheprogrammerbtw/husk)
9
12
 
10
13
  ## What is Husk?
11
14
 
12
- Most LLM calls are a brain in a jar — they can think, but can't act, remember, verify their own work, or show you what they did. **Husk** is the body, hands, memory, and nervous system you wrap around any LLM (Claude, GPT, Gemini, local models) to turn it into a real agent.
15
+ Most LLM calls are a **brain in a jar** — they can think, but can't act, remember, verify their own work, or show you what they did. **Husk** is the body, hands, memory, and nervous system you wrap around any LLM (Claude, GPT, Gemini, local models) to turn it into a real agent.
13
16
 
14
17
  ```ts
15
18
  import { Agent, AnthropicProvider, Read, Write, Edit, Bash, Grep, FileStore } from '@princetheprogrammerbtw/husk';
@@ -31,16 +34,27 @@ const result = await agent.run('Review src/core/agent.ts');
31
34
  console.log(result.output);
32
35
  ```
33
36
 
37
+ ## Why Husk?
38
+
39
+ | You're used to… | Husk gives you… |
40
+ |---|---|
41
+ | One-shot LLM calls with no memory | Persistent file-backed or in-memory memory across calls |
42
+ | Hand-rolled tool-calling loops | A small, typed event stream you can subscribe to |
43
+ | Tied to one provider's SDK | Provider-agnostic core; swap Anthropic ↔ OpenAI in one line |
44
+ | Reinventing agent loops in every project | Drop-in `Agent` class with stop conditions, parallel tool execution, and error recovery |
45
+ | No observability into what the model actually did | Typed events for every iteration, tool call, and provider response |
46
+
34
47
  ## Features
35
48
 
36
49
  - 🧠 **Provider-agnostic** — Anthropic, OpenAI, more coming. Bring your own model.
37
- - 🛠️ **5 built-in tools** — `Read`, `Write`, `Edit`, `Bash` (with safety denylist), `Grep` (ripgrep with grep fallback)
50
+ - 🛠️ **5 built-in tools** — `Read`, `Write`, `Edit`, `Bash` (with safety denylist for `rm -rf /`, fork bombs, etc.), `Grep` (ripgrep with grep fallback)
38
51
  - 💾 **Memory** — `InMemoryStore` for sessions, `FileStore` for persistence
39
52
  - 👀 **Observability** — typed event emitter, drop in any logger or tracer
40
53
  - 🧭 **Steering** — system prompts, numbered rules, few-shot examples
41
54
  - 🤝 **Sub-agents** — compose agents inside agents (see [multi-agent example](./examples/03-multi-agent))
42
- - 📦 **Batteries included** — 35KB ESM bundle, full TypeScript types
55
+ - 📦 **Batteries included** — 35KB ESM bundle, 26KB d.ts, zero runtime deps except the provider SDKs
43
56
  - 🖥️ **CLI** — `husk run "<prompt>"` for one-shot invocations
57
+ - 🔒 **Type-safe** — strict TypeScript, no `any`, full type definitions shipped
44
58
 
45
59
  ## Install
46
60
 
@@ -50,6 +64,8 @@ npm install @princetheprogrammerbtw/husk
50
64
  pnpm add @princetheprogrammerbtw/husk
51
65
  # or
52
66
  bun add @princetheprogrammerbtw/husk
67
+ # or
68
+ yarn add @princetheprogrammerbtw/husk
53
69
  ```
54
70
 
55
71
  You'll also need an API key for the provider you choose:
@@ -61,7 +77,7 @@ export OPENAI_API_KEY=sk-... # for GPT
61
77
 
62
78
  ## Quickstart
63
79
 
64
- The smallest possible agent:
80
+ The smallest possible agent — model, prompt, done:
65
81
 
66
82
  ```ts
67
83
  import { Agent, AnthropicProvider } from '@princetheprogrammerbtw/husk';
@@ -74,6 +90,41 @@ const result = await agent.run('What is the capital of France? Answer in one sen
74
90
  console.log(result.output); // "Paris"
75
91
  ```
76
92
 
93
+ A more realistic agent — with tools, memory, and steering:
94
+
95
+ ```ts
96
+ import {
97
+ Agent, AnthropicProvider, Read, Write, Edit, Bash, Grep,
98
+ FileStore, InMemoryStore,
99
+ } from '@princetheprogrammerbtw/husk';
100
+
101
+ const agent = new Agent({
102
+ model: new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY }),
103
+ tools: [Read, Write, Edit, Bash, Grep],
104
+ memory: new FileStore({ path: './.husk/memory' }),
105
+ steering: {
106
+ systemPrompt: 'You are a careful code reviewer.',
107
+ rules: [
108
+ 'Read the file in full before commenting.',
109
+ 'Cite specific line numbers for every finding.',
110
+ ],
111
+ },
112
+ });
113
+
114
+ const result = await agent.run('Review src/core/agent.ts');
115
+ ```
116
+
117
+ Swapping to OpenAI is a one-line change:
118
+
119
+ ```ts
120
+ import { OpenAIProvider } from '@princetheprogrammerbtw/husk';
121
+
122
+ const agent = new Agent({
123
+ model: new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY }),
124
+ // ...same config otherwise
125
+ });
126
+ ```
127
+
77
128
  ## CLI
78
129
 
79
130
  ```bash
@@ -84,9 +135,11 @@ husk run "Summarize README.md" --provider openai --model gpt-5
84
135
  husk run --help
85
136
  ```
86
137
 
138
+ The CLI wraps the same `Agent` class — flags map directly to `AgentConfig` fields.
139
+
87
140
  ## Examples
88
141
 
89
- Three worked examples in the `examples/` directory:
142
+ Three worked examples in the [`examples/`](./examples) directory:
90
143
 
91
144
  - **[01-hello-agent](./examples/01-hello-agent)** — minimal agent, no tools
92
145
  - **[02-code-reviewer](./examples/02-code-reviewer)** — full tool set + steering for code review
@@ -96,9 +149,10 @@ Run any example with `bun run examples/0X-name/index.ts`.
96
149
 
97
150
  ## Documentation
98
151
 
99
- - **[Learning Journal](./LEARNING.md)** — design decisions, trade-offs, and lessons learned
100
- - **[Changelog](./CHANGELOG.md)** — release history
101
- - **[Contributing](./CONTRIBUTING.md)** — how to contribute
152
+ - 📓 **[Learning Journal](./LEARNING.md)** — design decisions, trade-offs, and lessons learned while building
153
+ - 📋 **[Changelog](./CHANGELOG.md)** — release history
154
+ - 🤝 **[Contributing](./CONTRIBUTING.md)** — how to contribute
155
+ - 🏗️ **[Architecture](#architecture)** — the module layout, below
102
156
 
103
157
  ## Architecture
104
158
 
@@ -111,15 +165,26 @@ src/
111
165
  └── index.ts # public API surface
112
166
  ```
113
167
 
114
- Every piece composes through a typed event stream. The agent loop is ~150 lines. Provider adapters are the only files that know about provider-specific wire formats.
168
+ Every piece composes through a **typed event stream**. The agent loop is ~150 lines. Provider adapters are the only files that know about provider-specific wire formats. Tools are plain objects implementing a 4-field interface — register by passing an array to the Agent.
115
169
 
116
170
  ## Roadmap
117
171
 
118
172
  - **v0.1.0** ✅ Core loop, Anthropic + OpenAI, 5 built-in tools, memory, observability, CLI
173
+ - **v0.1.1** ✅ CLI shebang fix, version bump
119
174
  - **v0.2.0** Eval runner, OTel export, Ollama adapter
120
175
  - **v0.3.0** Vector memory, hosted dashboard
121
176
  - **v1.0.0** Stable API, marketplace, enterprise features
122
177
 
178
+ ## Contributing
179
+
180
+ PRs welcome! See [CONTRIBUTING.md](./CONTRIBUTING.md) for the dev setup, scripts, and commit conventions.
181
+
182
+ The project follows Conventional Commits. Every commit body explains *why*, not what — the diff already shows what.
183
+
184
+ ## Show your support
185
+
186
+ If Husk saves you time, ⭐️ the [GitHub repo](https://github.com/10xdev4u-alt/husk) — it helps others find the project. Issues, PRs, and feedback all welcome.
187
+
123
188
  ## License
124
189
 
125
- MIT © 2026 princetheprogrammerbtw
190
+ MIT © 2026 [princetheprogrammerbtw](https://github.com/10xdev4u-alt)
package/dist/index.d.ts CHANGED
@@ -525,6 +525,48 @@ declare class OpenAIProvider implements Provider {
525
525
  chat(request: ChatRequest): Promise<ChatResponse>;
526
526
  }
527
527
 
528
+ /**
529
+ * Husk — Ollama provider adapter.
530
+ *
531
+ * Wraps Ollama's OpenAI-compatible Chat Completions API. Because Ollama
532
+ * exposes the exact same wire format as OpenAI, we can reuse the OpenAI
533
+ * adapter internally — only the default model name, base URL, and the
534
+ * provider 'name' field differ.
535
+ *
536
+ * Why this exists: local models (llama3.2, deepseek-r1, qwen2.5, etc.)
537
+ * are a first-class use case. Privacy, cost, and offline-ability all
538
+ * matter. Ollama is the dominant local-model runtime and uses the
539
+ * OpenAI API surface, so the adapter is a thin shell.
540
+ *
541
+ * Defaults:
542
+ * - model: 'llama3.2' (override via constructor)
543
+ * - baseURL: 'http://localhost:11434/v1' (override for remote Ollama)
544
+ * - apiKey: 'ollama' (Ollama ignores the value but the OpenAI SDK
545
+ * requires a non-empty string)
546
+ *
547
+ * Usage:
548
+ * const agent = new Agent({ model: new OllamaProvider() });
549
+ * const result = await agent.run('Explain quantum entanglement');
550
+ *
551
+ * For a list of models: `ollama list` (in your terminal).
552
+ */
553
+
554
+ interface OllamaProviderOptions {
555
+ /** Model id (run `ollama list` to see what's pulled locally). Default: 'llama3.2'. */
556
+ readonly model?: string;
557
+ /** Ollama server URL. Default: 'http://localhost:11434/v1'. */
558
+ readonly baseURL?: string;
559
+ /** API key — Ollama ignores this but the OpenAI SDK requires it. Default: 'ollama'. */
560
+ readonly apiKey?: string;
561
+ }
562
+ declare class OllamaProvider implements Provider {
563
+ readonly name = "ollama";
564
+ readonly model: string;
565
+ private readonly inner;
566
+ constructor(options?: OllamaProviderOptions);
567
+ chat(request: Parameters<Provider['chat']>[0]): ReturnType<Provider['chat']>;
568
+ }
569
+
528
570
  /**
529
571
  * Husk — tool registry helpers.
530
572
  *
@@ -688,6 +730,232 @@ interface GrepInput {
688
730
  }
689
731
  declare const Grep: ToolDefinition<GrepInput>;
690
732
 
733
+ /**
734
+ * Husk — eval runner types and API.
735
+ *
736
+ * The eval runner lets users assert that an agent's output meets
737
+ * expectations. Three primitives:
738
+ *
739
+ * 1. EvalCase — an input + the expected outcome (an assertion or a set of them)
740
+ * 2. Assertion — a function that takes the agent's result and returns pass/fail
741
+ * 3. EvalSuite — a named collection of eval cases, runnable as a unit
742
+ *
743
+ * The design choice: assertions are plain async functions, not a DSL.
744
+ * Users can use the 4 built-ins (equals, contains, matches, fn) or
745
+ * write their own. The DSL is intentionally tiny — a heavy DSL
746
+ * (think Jest matchers) is a maintainability trap.
747
+ *
748
+ * Example:
749
+ *
750
+ * const suite = defineSuite({
751
+ * name: 'hello-agent',
752
+ * cases: [
753
+ * {
754
+ * name: 'answers geography',
755
+ * input: 'What is the capital of France? Answer in one word.',
756
+ * assertions: [
757
+ * contains('Paris'),
758
+ * matches(/^[A-Z][a-z]+$/), // single capitalized word
759
+ * ],
760
+ * },
761
+ * ],
762
+ * });
763
+ *
764
+ * const results = await runSuite(suite, () => new Agent({ model: ... }));
765
+ * console.log(`${results.passed}/${results.total} passed`);
766
+ */
767
+
768
+ /**
769
+ * A function that checks whether an agent's output meets a criterion.
770
+ * Returns a pass/fail with an optional message explaining the failure.
771
+ */
772
+ type Assertion = (result: AgentResult) => AssertionResult | Promise<AssertionResult>;
773
+ interface AssertionResult {
774
+ /** Whether the assertion passed. */
775
+ readonly pass: boolean;
776
+ /** Human-readable name shown in eval reports. */
777
+ readonly name: string;
778
+ /** Optional message — required when pass is false to explain why. */
779
+ readonly message?: string;
780
+ }
781
+ /** Output exactly equals the expected string. */
782
+ declare function equals(expected: string): Assertion;
783
+ /** Output contains the expected substring (case-sensitive). */
784
+ declare function contains(needle: string): Assertion;
785
+ /** Output matches the expected regex. */
786
+ declare function matches(pattern: RegExp): Assertion;
787
+ /** Output passes a custom predicate. Use this for shape-based checks. */
788
+ declare function fn(name: string, predicate: (output: string) => boolean, message?: string): Assertion;
789
+ /** Output does NOT contain the given substring. */
790
+ declare function notContains(needle: string): Assertion;
791
+ /** Output length is within bounds. */
792
+ declare function lengthBetween(min: number, max: number): Assertion;
793
+ interface EvalCase {
794
+ /** Human-readable name shown in eval reports. */
795
+ readonly name: string;
796
+ /** The input to pass to agent.run(). */
797
+ readonly input: string;
798
+ /** Assertions to run on the result. All must pass for the case to pass. */
799
+ readonly assertions: readonly Assertion[];
800
+ /**
801
+ * Optional max iterations override. Lets you cap runaway agents per-case
802
+ * without affecting other cases in the suite.
803
+ */
804
+ readonly maxIterations?: number;
805
+ }
806
+ interface EvalSuite {
807
+ /** Suite name shown in reports. */
808
+ readonly name: string;
809
+ /** Cases in this suite, run sequentially. */
810
+ readonly cases: readonly EvalCase[];
811
+ }
812
+ interface CaseResult {
813
+ readonly caseName: string;
814
+ readonly passed: boolean;
815
+ readonly assertionResults: readonly AssertionResult[];
816
+ readonly agentResult: AgentResult;
817
+ readonly durationMs: number;
818
+ }
819
+ interface SuiteResult {
820
+ readonly suiteName: string;
821
+ readonly results: readonly CaseResult[];
822
+ readonly passed: number;
823
+ readonly total: number;
824
+ readonly durationMs: number;
825
+ }
826
+
827
+ /**
828
+ * Husk — eval runner.
829
+ *
830
+ * Takes an EvalSuite + a factory that returns an Agent, runs each
831
+ * case sequentially, applies the assertions, and reports results.
832
+ *
833
+ * Why a factory (not an Agent instance): each case might want its
834
+ * own agent configuration. The factory pattern gives the user full
835
+ * control without forcing a specific shape.
836
+ *
837
+ * Why sequential (not parallel): LLM calls compete for rate limits
838
+ * and cost $$$. Sequential gives predictable billing and easier
839
+ * debugging. Parallel mode is a v0.3.0 addition.
840
+ *
841
+ * Failure handling: an agent run that throws an error is reported
842
+ * as a case failure (not a runner crash). The error message is
843
+ * included in the assertion results so the user can see what broke.
844
+ */
845
+
846
+ /**
847
+ * A factory that produces a fresh Agent per case. Called once per
848
+ * case so each case can have isolated memory, config, etc.
849
+ */
850
+ type AgentFactory = () => Agent | Promise<Agent>;
851
+ interface RunSuiteOptions {
852
+ /** Stop on first failing case. Default: false (run all cases regardless). */
853
+ readonly failFast?: boolean;
854
+ /** Custom logger for runner-level events. Default: silent. */
855
+ readonly onCaseStart?: (caseName: string) => void;
856
+ readonly onCaseEnd?: (result: CaseResult) => void;
857
+ }
858
+ declare function runSuite(suite: EvalSuite, factory: AgentFactory, options?: RunSuiteOptions): Promise<SuiteResult>;
859
+ /**
860
+ * Build a suite with less boilerplate. Equivalent to constructing
861
+ * the object inline, but reads more clearly at the call site.
862
+ */
863
+ declare function defineSuite(suite: {
864
+ name: string;
865
+ cases: readonly EvalCase[];
866
+ }): EvalSuite;
867
+
868
+ /**
869
+ * Husk — observability types (tracer interface).
870
+ *
871
+ * A minimal, OTel-inspired tracer interface. Husk's events are mapped
872
+ * to spans by the mapper in ./tracer.ts. Users can plug in the real
873
+ * @opentelemetry/api tracer via the adapter (see ./otel-adapter.ts)
874
+ * or any other compatible backend.
875
+ *
876
+ * Design choice: we don't depend on @opentelemetry/api directly. The
877
+ * interface here is a strict subset of OTel's Span interface (just
878
+ * what's needed for agent observability). Keeping the dep out of
879
+ * Husk's core means users who don't need OTel pay nothing for it.
880
+ *
881
+ * For users who want full OTel:
882
+ * import { trace } from '@opentelemetry/api';
883
+ * import { toOtelTracer } from '@princetheprogrammerbtw/husk/otel-adapter';
884
+ * agent.onAny(toOtelTracer(trace.getTracer('husk')).onEvent);
885
+ */
886
+ type SpanKind = 'internal' | 'client' | 'server';
887
+ interface SpanContext {
888
+ /** Unique trace id (all spans in one agent.run share this). */
889
+ readonly traceId: string;
890
+ /** Unique span id. */
891
+ readonly spanId: string;
892
+ /** Parent span id, if any. */
893
+ readonly parentSpanId?: string;
894
+ }
895
+ interface SpanOptions {
896
+ readonly name: string;
897
+ readonly kind?: SpanKind;
898
+ readonly attributes?: Readonly<Record<string, unknown>>;
899
+ readonly startTimeNs?: bigint;
900
+ }
901
+ interface Span {
902
+ readonly context: SpanContext;
903
+ /** Record an event (timestamped annotation) on the span. */
904
+ addEvent(name: string, attributes?: Record<string, unknown>): void;
905
+ /** Set or update an attribute on the span. */
906
+ setAttribute(key: string, value: string | number | boolean | null): void;
907
+ /** Record an exception. */
908
+ recordException(err: Error): void;
909
+ /** Mark the span as failed. */
910
+ setStatus(status: 'ok' | 'error', message?: string): void;
911
+ /** End the span. Must be called exactly once. */
912
+ end(endTimeNs?: bigint): void;
913
+ }
914
+ interface Tracer {
915
+ /**
916
+ * Start a new span. If parent is provided, the new span becomes a
917
+ * child of it. Returns the new span; caller is responsible for
918
+ * calling .end() on it.
919
+ */
920
+ startSpan(options: SpanOptions, parent?: SpanContext): Span;
921
+ }
922
+ /**
923
+ * A tracer that does nothing. Used when no real tracer is configured.
924
+ * Zero overhead — every method is a no-op, so the cost is one virtual
925
+ * call per event.
926
+ */
927
+ declare class NoopTracer implements Tracer {
928
+ startSpan(_options: SpanOptions, _parent?: SpanContext): Span;
929
+ }
930
+
931
+ /**
932
+ * Husk — agent event → tracer mapper.
933
+ *
934
+ * Translates the typed AgentEvent stream into tracer spans. The top-
935
+ * level 'agent:start' begins a trace, each iteration becomes a child
936
+ * span, and tool calls become their own spans under the iteration.
937
+ *
938
+ * Design: spans are created in startSpanOrder. Tool spans nest under
939
+ * the iteration span. The end of the agent run ends the trace span.
940
+ *
941
+ * Usage:
942
+ * const mapper = new EventTracer(myTracer);
943
+ * agent.onAny(mapper.onEvent.bind(mapper));
944
+ * await agent.run(...); // emits spans to myTracer
945
+ */
946
+
947
+ declare class EventTracer {
948
+ private readonly tracer;
949
+ private traceSpan;
950
+ private iterationSpan;
951
+ private toolSpans;
952
+ constructor(tracer: Tracer);
953
+ /**
954
+ * Bind as an event handler: `agent.onAny(tracer.onEvent.bind(tracer))`
955
+ */
956
+ onEvent: AgentEventHandler;
957
+ }
958
+
691
959
  /**
692
960
  * Husk — public API entry point.
693
961
  *
@@ -699,4 +967,4 @@ declare const Grep: ToolDefinition<GrepInput>;
699
967
  */
700
968
  declare const VERSION = "0.1.0";
701
969
 
702
- export { Agent, type AgentConfig, type AgentEvent, AgentEventEmitter, type AgentEventHandler, type AgentResult, AnthropicProvider, type AnthropicProviderOptions, Bash, type BashInput, type ChatChunk, type ChatRequest, type ChatResponse, ConsoleLogger, type ContentBlock, Edit, type EditInput, type Example, FileStore, type FileStoreOptions, Grep, type GrepInput, InMemoryStore, type JSONSchema, type JSONSchemaField, type LogLevel, type Logger, type MemoryStore, type Message, type MessageContent, OpenAIProvider, type OpenAIProviderOptions, type Provider, Read, type ReadInput, type Role, type SteeringConfig, type StopReason, type TextBlock, type TokenUsage, type ToolContext, type ToolDefinition, type ToolResult, type ToolResultBlock, type ToolUseBlock, VERSION, Write, type WriteInput, arrayField, booleanField, buildExampleMessages, buildSystemPrompt, defineTool, integerField, logEventsTo, numberField, objectField, objectSchema, stringField };
970
+ export { Agent, type AgentConfig, type AgentEvent, AgentEventEmitter, type AgentEventHandler, type AgentFactory, type AgentResult, AnthropicProvider, type AnthropicProviderOptions, type Assertion, type AssertionResult, Bash, type BashInput, type CaseResult, type ChatChunk, type ChatRequest, type ChatResponse, ConsoleLogger, type ContentBlock, Edit, type EditInput, type EvalCase, type EvalSuite, EventTracer, type Example, FileStore, type FileStoreOptions, Grep, type GrepInput, InMemoryStore, type JSONSchema, type JSONSchemaField, type LogLevel, type Logger, type MemoryStore, type Message, type MessageContent, NoopTracer, OllamaProvider, type OllamaProviderOptions, OpenAIProvider, type OpenAIProviderOptions, type Provider, Read, type ReadInput, type Role, type RunSuiteOptions, type Span, type SpanContext, type SpanKind, type SpanOptions, type SteeringConfig, type StopReason, type SuiteResult, type TextBlock, type TokenUsage, type ToolContext, type ToolDefinition, type ToolResult, type ToolResultBlock, type ToolUseBlock, type Tracer, VERSION, Write, type WriteInput, arrayField, booleanField, buildExampleMessages, buildSystemPrompt, contains, defineSuite, defineTool, equals, fn, integerField, lengthBetween, logEventsTo, matches, notContains, numberField, objectField, objectSchema, runSuite, stringField };