@infinityi/engine-lib 1.0.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/LICENSE +21 -0
- package/README.md +488 -0
- package/dist/agent/agent-registry.d.ts +46 -0
- package/dist/agent/as-tool.d.ts +64 -0
- package/dist/agent/define.d.ts +35 -0
- package/dist/agent/handoff.d.ts +39 -0
- package/dist/agent/index.d.ts +20 -0
- package/dist/agent/index.js +38 -0
- package/dist/agent/registry.d.ts +27 -0
- package/dist/agent/types.d.ts +109 -0
- package/dist/context/index.d.ts +11 -0
- package/dist/context/index.js +21 -0
- package/dist/context/providers.d.ts +25 -0
- package/dist/context/types.d.ts +63 -0
- package/dist/context/window.d.ts +41 -0
- package/dist/errors.d.ts +93 -0
- package/dist/errors.js +24 -0
- package/dist/events/hub.d.ts +15 -0
- package/dist/events/index.d.ts +26 -0
- package/dist/events/index.js +24 -0
- package/dist/events/subscribers.d.ts +57 -0
- package/dist/events/telemetry.d.ts +61 -0
- package/dist/events/types.d.ts +39 -0
- package/dist/execution/index.d.ts +11 -0
- package/dist/execution/index.js +22 -0
- package/dist/execution/run.d.ts +35 -0
- package/dist/execution/types.d.ts +203 -0
- package/dist/execution/usage.d.ts +14 -0
- package/dist/index-02s1fjxr.js +226 -0
- package/dist/index-19pwq79t.js +0 -0
- package/dist/index-1p6mb2vz.js +32 -0
- package/dist/index-64tt9696.js +1796 -0
- package/dist/index-7690reng.js +96 -0
- package/dist/index-bqg01r42.js +354 -0
- package/dist/index-d4xz3abn.js +0 -0
- package/dist/index-dexgmwg6.js +148 -0
- package/dist/index-fkr3rcq9.js +97 -0
- package/dist/index-jg19te9v.js +0 -0
- package/dist/index-jp2b31xs.js +101 -0
- package/dist/index-jxgj4z08.js +68 -0
- package/dist/index-kte2h4k2.js +0 -0
- package/dist/index-pwr8179t.js +492 -0
- package/dist/index-rentvdpp.js +27 -0
- package/dist/index-vnby35rm.js +84 -0
- package/dist/index-w34cbktd.js +14 -0
- package/dist/index-xsv43c5j.js +39 -0
- package/dist/index-yrqrxwjt.js +148 -0
- package/dist/index-zfgr4xx3.js +90 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +117 -0
- package/dist/lifecycle/component.d.ts +74 -0
- package/dist/lifecycle/index.d.ts +12 -0
- package/dist/lifecycle/index.js +72 -0
- package/dist/messages/factory.d.ts +24 -0
- package/dist/messages/index.d.ts +8 -0
- package/dist/messages/index.js +17 -0
- package/dist/messages/types.d.ts +52 -0
- package/dist/providers/adapter.d.ts +42 -0
- package/dist/providers/anthropic/index.d.ts +31 -0
- package/dist/providers/anthropic/map.d.ts +12 -0
- package/dist/providers/anthropic/stream.d.ts +9 -0
- package/dist/providers/google/index.d.ts +29 -0
- package/dist/providers/google/map.d.ts +13 -0
- package/dist/providers/google/stream.d.ts +11 -0
- package/dist/providers/http.d.ts +61 -0
- package/dist/providers/index.d.ts +32 -0
- package/dist/providers/index.js +35 -0
- package/dist/providers/openai/index.d.ts +34 -0
- package/dist/providers/openai/map.d.ts +10 -0
- package/dist/providers/openai/stream.d.ts +9 -0
- package/dist/providers/openai-compatible/index.d.ts +37 -0
- package/dist/providers/openai-compatible/map.d.ts +13 -0
- package/dist/providers/openai-compatible/stream.d.ts +11 -0
- package/dist/providers/shared.d.ts +34 -0
- package/dist/providers/sse.d.ts +19 -0
- package/dist/providers/stream.d.ts +69 -0
- package/dist/providers/types.d.ts +137 -0
- package/dist/runtime/index.d.ts +11 -0
- package/dist/runtime/index.js +11 -0
- package/dist/runtime/secret.d.ts +12 -0
- package/dist/runtime/types.d.ts +27 -0
- package/dist/schema/builder.d.ts +70 -0
- package/dist/schema/index.d.ts +13 -0
- package/dist/schema/index.js +15 -0
- package/dist/schema/json-schema.d.ts +19 -0
- package/dist/schema/types.d.ts +70 -0
- package/dist/schema/validate.d.ts +19 -0
- package/dist/session/index.d.ts +11 -0
- package/dist/session/index.js +8 -0
- package/dist/session/session.d.ts +31 -0
- package/dist/session/store.d.ts +20 -0
- package/dist/session/types.d.ts +55 -0
- package/dist/testing/conformance.d.ts +106 -0
- package/dist/testing/conformance.js +132 -0
- package/dist/testing/index.d.ts +84 -0
- package/dist/testing/index.js +31 -0
- package/dist/tools/define.d.ts +42 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/result.d.ts +36 -0
- package/dist/tools/types.d.ts +85 -0
- package/docs/README.md +36 -0
- package/examples/README.md +24 -0
- package/examples/incident-analysis.ts +100 -0
- package/examples/lifecycle.ts +53 -0
- package/examples/multi-agent.ts +93 -0
- package/examples/terminal-coder.ts +80 -0
- package/package.json +114 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unified streaming model shared by every provider adapter.
|
|
3
|
+
*
|
|
4
|
+
* Each adapter translates its vendor's SSE events into this {@link StreamEvent}
|
|
5
|
+
* union. The stable application contract is the `StreamEvent` union itself;
|
|
6
|
+
* {@link StreamAccumulator} and {@link collectStream} are advanced helpers for
|
|
7
|
+
* adapter authors, tests, and provider-subpath users.
|
|
8
|
+
*
|
|
9
|
+
* The shape follows the rule every provider doc calls out: assemble tool-call
|
|
10
|
+
* arguments by **index**, never assume one flat string.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { ProviderError } from "../errors";
|
|
15
|
+
import type { CompletionResult, FinishReason, Usage } from "./types";
|
|
16
|
+
/**
|
|
17
|
+
* A single normalized streaming event.
|
|
18
|
+
*
|
|
19
|
+
* A well-formed stream starts with `message_start`, then yields zero or more
|
|
20
|
+
* text/tool-call delta events, and ends with `finish`. `error` may appear when
|
|
21
|
+
* a provider reports a recoverable stream error; thrown stream failures surface
|
|
22
|
+
* as `ProviderError`.
|
|
23
|
+
*
|
|
24
|
+
* Tool-call argument chunks are keyed by `index`: consumers must assemble
|
|
25
|
+
* `tool_call_delta` events by index and wait for `tool_call_end`.
|
|
26
|
+
*/
|
|
27
|
+
export type StreamEvent = {
|
|
28
|
+
readonly type: "message_start";
|
|
29
|
+
readonly model: string;
|
|
30
|
+
} | {
|
|
31
|
+
readonly type: "text_delta";
|
|
32
|
+
readonly text: string;
|
|
33
|
+
} | {
|
|
34
|
+
readonly type: "tool_call_start";
|
|
35
|
+
readonly index: number;
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly name: string;
|
|
38
|
+
} | {
|
|
39
|
+
readonly type: "tool_call_delta";
|
|
40
|
+
readonly index: number;
|
|
41
|
+
readonly argumentsTextDelta: string;
|
|
42
|
+
} | {
|
|
43
|
+
readonly type: "tool_call_end";
|
|
44
|
+
readonly index: number;
|
|
45
|
+
} | {
|
|
46
|
+
readonly type: "finish";
|
|
47
|
+
readonly finishReason: FinishReason;
|
|
48
|
+
readonly usage?: Usage;
|
|
49
|
+
} | {
|
|
50
|
+
readonly type: "error";
|
|
51
|
+
readonly error: ProviderError;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Folds a {@link StreamEvent} sequence into a single {@link CompletionResult}.
|
|
55
|
+
* Tool calls are keyed by their stream index so out-of-order deltas assemble
|
|
56
|
+
* correctly.
|
|
57
|
+
*/
|
|
58
|
+
export declare class StreamAccumulator {
|
|
59
|
+
private model?;
|
|
60
|
+
private text;
|
|
61
|
+
private finishReason;
|
|
62
|
+
private usage?;
|
|
63
|
+
private readonly toolCalls;
|
|
64
|
+
push(event: StreamEvent): void;
|
|
65
|
+
/** Build the final result. `model` is a fallback when no `message_start` was seen. */
|
|
66
|
+
result(model: string, raw?: unknown): CompletionResult;
|
|
67
|
+
}
|
|
68
|
+
/** Drain an event stream into a {@link CompletionResult}. */
|
|
69
|
+
export declare function collectStream(events: AsyncIterable<StreamEvent>, model: string, raw?: unknown): Promise<CompletionResult>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The normalized LLM provider contract.
|
|
3
|
+
*
|
|
4
|
+
* A {@link Provider} hides each vendor's wire format behind two methods —
|
|
5
|
+
* {@link Provider.complete} (one buffered turn) and {@link Provider.stream}
|
|
6
|
+
* (a unified delta stream) — both speaking the Phase-1 {@link Message} model
|
|
7
|
+
* and {@link JsonSchema} tool/output schemas. Adapters translate to/from the
|
|
8
|
+
* provider's native shape; nothing above this layer knows which vendor is in
|
|
9
|
+
* use. The stable application surface is the {@link Provider} contract, request
|
|
10
|
+
* / result / stream types, capabilities, and the built-in provider factories.
|
|
11
|
+
* Adapter scaffolding lives on `@infinityi/engine-lib/providers` as an advanced extension
|
|
12
|
+
* surface.
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import type { Message } from "../messages/types";
|
|
17
|
+
import type { EngineContext } from "../runtime/types";
|
|
18
|
+
import type { JsonSchema } from "../schema/types";
|
|
19
|
+
import type { StreamEvent } from "./stream";
|
|
20
|
+
/** A tool advertised to the model: a name plus JSON-Schema parameters. */
|
|
21
|
+
export interface ProviderTool {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly description?: string;
|
|
24
|
+
/** JSON Schema for the arguments object (from a Phase-1 `Schema.jsonSchema`). */
|
|
25
|
+
readonly parameters: JsonSchema;
|
|
26
|
+
}
|
|
27
|
+
/** How the model is allowed to use tools this turn. */
|
|
28
|
+
export type ToolChoice = "auto" | "none" | "required" | {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
};
|
|
31
|
+
/** Request a structured (JSON-Schema-constrained) response. */
|
|
32
|
+
export interface ResponseSchema {
|
|
33
|
+
readonly name: string;
|
|
34
|
+
readonly schema: JsonSchema;
|
|
35
|
+
/** Enforce exact schema conformance where the provider supports it. Default `true`. */
|
|
36
|
+
readonly strict?: boolean;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A provider-neutral request for a single model turn.
|
|
40
|
+
*
|
|
41
|
+
* `model` overrides the provider's `defaultModel` for this request only.
|
|
42
|
+
* Generation knobs are normalized across providers. `providerOptions` is the
|
|
43
|
+
* sanctioned escape hatch for vendor-specific fields that are not yet
|
|
44
|
+
* first-classed in this interface.
|
|
45
|
+
*/
|
|
46
|
+
export interface CompletionRequest {
|
|
47
|
+
/** Model id; falls back to the provider's `defaultModel` when omitted. */
|
|
48
|
+
readonly model?: string;
|
|
49
|
+
/** Conversation so far (Phase-1 model); adapters extract any system message. */
|
|
50
|
+
readonly messages: Message[];
|
|
51
|
+
/** Provider-facing tool declarations for this turn. */
|
|
52
|
+
readonly tools?: ProviderTool[];
|
|
53
|
+
/** How the model may use tools this turn. */
|
|
54
|
+
readonly toolChoice?: ToolChoice;
|
|
55
|
+
/** Optional structured-output schema for providers that support it. */
|
|
56
|
+
readonly responseSchema?: ResponseSchema;
|
|
57
|
+
/** Maximum tokens the model may generate in the response. */
|
|
58
|
+
readonly maxOutputTokens?: number;
|
|
59
|
+
/** Sampling temperature, provider-normalized where possible. */
|
|
60
|
+
readonly temperature?: number;
|
|
61
|
+
/** Nucleus sampling value, provider-normalized where possible. */
|
|
62
|
+
readonly topP?: number;
|
|
63
|
+
/** Stop sequences passed through when supported. */
|
|
64
|
+
readonly stopSequences?: readonly string[];
|
|
65
|
+
/** Vendor-neutral request metadata (e.g. an end-user id). */
|
|
66
|
+
readonly metadata?: Record<string, string>;
|
|
67
|
+
/**
|
|
68
|
+
* Escape hatch merged into the provider request body, for features not yet
|
|
69
|
+
* first-classed here (reasoning/thinking knobs, server-side built-in tools,
|
|
70
|
+
* safety settings, stateful conversation ids, …).
|
|
71
|
+
*/
|
|
72
|
+
readonly providerOptions?: Record<string, unknown>;
|
|
73
|
+
}
|
|
74
|
+
/** Token accounting, normalized across providers. */
|
|
75
|
+
export interface Usage {
|
|
76
|
+
readonly inputTokens: number;
|
|
77
|
+
readonly outputTokens: number;
|
|
78
|
+
readonly totalTokens: number;
|
|
79
|
+
/** Reasoning/thinking tokens, when the provider reports them separately. */
|
|
80
|
+
readonly reasoningTokens?: number;
|
|
81
|
+
/** Prompt tokens served from cache, when reported. */
|
|
82
|
+
readonly cachedInputTokens?: number;
|
|
83
|
+
}
|
|
84
|
+
/** Why the model stopped generating, normalized across providers. */
|
|
85
|
+
export type FinishReason = "stop" | "length" | "tool_calls" | "content_filter" | "error" | "other";
|
|
86
|
+
/** A tool call the model requested. `arguments` is parsed JSON when possible. */
|
|
87
|
+
export interface ToolCall {
|
|
88
|
+
/** Correlation id (OpenAI `call_id` / Anthropic `tool_use.id` / Gemini `functionCall.id`). */
|
|
89
|
+
readonly id: string;
|
|
90
|
+
readonly name: string;
|
|
91
|
+
/** Parsed arguments object, or `undefined` if the raw text was not valid JSON. */
|
|
92
|
+
readonly arguments: unknown;
|
|
93
|
+
/** Raw arguments text as emitted by the model (always preserved). */
|
|
94
|
+
readonly argumentsText?: string;
|
|
95
|
+
}
|
|
96
|
+
/** The normalized result of a single completion. */
|
|
97
|
+
export interface CompletionResult {
|
|
98
|
+
/** Assistant message in the Phase-1 model (text + tool-call parts). */
|
|
99
|
+
readonly message: Message;
|
|
100
|
+
/** Tool calls surfaced from the message, for convenience. */
|
|
101
|
+
readonly toolCalls: ToolCall[];
|
|
102
|
+
readonly finishReason: FinishReason;
|
|
103
|
+
readonly usage?: Usage;
|
|
104
|
+
/** The model id that produced this result. */
|
|
105
|
+
readonly model: string;
|
|
106
|
+
/**
|
|
107
|
+
* The provider-native response object. This intentionally remains `unknown`:
|
|
108
|
+
* consumers may narrow it when they know the adapter, while engine-lib keeps
|
|
109
|
+
* the normalized result portable.
|
|
110
|
+
*/
|
|
111
|
+
readonly raw: unknown;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Declared, queryable provider capabilities so callers can degrade gracefully.
|
|
115
|
+
*
|
|
116
|
+
* Adapter authors should treat these as capability truth: the conformance suite
|
|
117
|
+
* validates that built-in adapters are honest about supported features.
|
|
118
|
+
*/
|
|
119
|
+
export interface ProviderCapabilities {
|
|
120
|
+
readonly tools: boolean;
|
|
121
|
+
readonly streaming: boolean;
|
|
122
|
+
readonly multimodalInput: boolean;
|
|
123
|
+
readonly parallelToolCalls: boolean;
|
|
124
|
+
readonly structuredOutput: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** The normalized LLM provider contract. */
|
|
127
|
+
export interface Provider {
|
|
128
|
+
/** Stable provider id, e.g. `"openai"`, `"anthropic"`, `"google"`. */
|
|
129
|
+
readonly name: string;
|
|
130
|
+
/** Model used when a {@link CompletionRequest} omits `model`. */
|
|
131
|
+
readonly defaultModel: string;
|
|
132
|
+
readonly capabilities: ProviderCapabilities;
|
|
133
|
+
/** Run one turn and return the buffered, normalized result. */
|
|
134
|
+
complete(req: CompletionRequest, ctx?: EngineContext): Promise<CompletionResult>;
|
|
135
|
+
/** Run one turn, yielding a unified stream of {@link StreamEvent}s. */
|
|
136
|
+
stream(req: CompletionRequest, ctx?: EngineContext): AsyncIterable<StreamEvent>;
|
|
137
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@infinityi/engine-lib/runtime` — the forge integration surface.
|
|
3
|
+
*
|
|
4
|
+
* Re-exports forge's `Secret` helpers so hosts wiring config-sourced
|
|
5
|
+
* credentials don't need to dual-import from `@infinityi/forge/config`.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
export { resolveSecret } from "./secret";
|
|
10
|
+
export type { EngineContext, Logger, Telemetry, TelemetryHandle } from "./types";
|
|
11
|
+
export { isSecret, Secret } from "@infinityi/forge/config";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge to `forge/config` secrets.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Secret } from "@infinityi/forge/config";
|
|
7
|
+
/**
|
|
8
|
+
* Unwrap a forge {@link Secret} or pass a raw string through, so provider
|
|
9
|
+
* adapters (Phase 2) can accept either an inline key or a config-sourced
|
|
10
|
+
* secret without each adapter re-implementing the check.
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveSecret(value: string | Secret<string>): string;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forge integration conventions threaded through engine-lib.
|
|
3
|
+
*
|
|
4
|
+
* Observability is expressed entirely in terms of forge's `Telemetry`
|
|
5
|
+
* handle and `Logger`, so engine-lib never invents its own logging or
|
|
6
|
+
* metrics surface.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import type { Telemetry } from "@infinityi/forge/telemetry";
|
|
11
|
+
import type { Logger } from "@infinityi/forge/telemetry/log";
|
|
12
|
+
/** The unit of observability threaded through engine-lib (forge's `Telemetry` handle). */
|
|
13
|
+
export type TelemetryHandle = Telemetry;
|
|
14
|
+
/**
|
|
15
|
+
* Options common to every engine-lib entry point (provider calls in
|
|
16
|
+
* Phase 2, agent runs in Phase 4). All fields are optional so the library
|
|
17
|
+
* is usable with zero observability wiring.
|
|
18
|
+
*/
|
|
19
|
+
export interface EngineContext {
|
|
20
|
+
/** Forge telemetry handle for traces / metrics / logs. */
|
|
21
|
+
readonly telemetry?: TelemetryHandle;
|
|
22
|
+
/** Structured logger (defaults to `telemetry.log` when omitted). */
|
|
23
|
+
readonly logger?: Logger;
|
|
24
|
+
/** Cancellation signal honored by long-running operations (Phase 4). */
|
|
25
|
+
readonly signal?: AbortSignal;
|
|
26
|
+
}
|
|
27
|
+
export type { Logger, Telemetry };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `s` builder — the public entry point for declaring schemas.
|
|
3
|
+
*
|
|
4
|
+
* `s` constructs {@link Schema} values for the JSON-Schema-expressible types
|
|
5
|
+
* engine-lib needs to describe tool parameters and structured outputs. Objects
|
|
6
|
+
* are strict by default (`additionalProperties: false`), and fields wrapped in
|
|
7
|
+
* `s.optional()` infer as optional TypeScript properties. It is intentionally
|
|
8
|
+
* dependency-free; external schema libraries (e.g. Zod) plug in through
|
|
9
|
+
* `asSchema` rather than as a hard dependency.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { s, type Infer } from "@infinityi/engine-lib/schema";
|
|
14
|
+
*
|
|
15
|
+
* const Params = s.object({
|
|
16
|
+
* service: s.string(),
|
|
17
|
+
* lines: s.optional(s.number({ int: true })),
|
|
18
|
+
* });
|
|
19
|
+
* type Params = Infer<typeof Params>; // { service: string; lines?: number }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import type { OptionalSchema, Schema } from "./types";
|
|
25
|
+
type ObjectShape = Record<string, Schema<unknown>>;
|
|
26
|
+
type OptionalKeys<P extends ObjectShape> = {
|
|
27
|
+
[K in keyof P]: P[K] extends OptionalSchema<unknown> ? K : never;
|
|
28
|
+
}[keyof P];
|
|
29
|
+
type RequiredKeys<P extends ObjectShape> = Exclude<keyof P, OptionalKeys<P>>;
|
|
30
|
+
type InferShape<P extends ObjectShape> = {
|
|
31
|
+
[K in RequiredKeys<P>]: P[K] extends Schema<infer T> ? T : never;
|
|
32
|
+
} & {
|
|
33
|
+
[K in OptionalKeys<P>]?: P[K] extends Schema<infer T> ? Exclude<T, undefined> : never;
|
|
34
|
+
};
|
|
35
|
+
/** Public schema-builder surface. */
|
|
36
|
+
export declare const s: {
|
|
37
|
+
/** A string, optionally constrained to an enum. */
|
|
38
|
+
readonly string: (opts?: {
|
|
39
|
+
description?: string;
|
|
40
|
+
enum?: readonly string[];
|
|
41
|
+
}) => Schema<string>;
|
|
42
|
+
/** A number. Pass `{ int: true }` to require an integer. */
|
|
43
|
+
readonly number: (opts?: {
|
|
44
|
+
description?: string;
|
|
45
|
+
int?: boolean;
|
|
46
|
+
}) => Schema<number>;
|
|
47
|
+
/** A boolean. */
|
|
48
|
+
readonly boolean: (opts?: {
|
|
49
|
+
description?: string;
|
|
50
|
+
}) => Schema<boolean>;
|
|
51
|
+
/** One of a fixed set of string variants. */
|
|
52
|
+
readonly enum: <V extends string>(values: readonly V[], opts?: {
|
|
53
|
+
description?: string;
|
|
54
|
+
}) => Schema<V>;
|
|
55
|
+
/** An array of `item`. */
|
|
56
|
+
readonly array: <T>(item: Schema<T>, opts?: {
|
|
57
|
+
description?: string;
|
|
58
|
+
}) => Schema<T[]>;
|
|
59
|
+
/**
|
|
60
|
+
* An object with the given properties. Properties wrapped in
|
|
61
|
+
* {@link s.optional} are excluded from `required`; all others are required.
|
|
62
|
+
* Unknown properties are rejected (`additionalProperties: false`).
|
|
63
|
+
*/
|
|
64
|
+
readonly object: <P extends ObjectShape>(props: P, opts?: {
|
|
65
|
+
description?: string;
|
|
66
|
+
}) => Schema<InferShape<P>>;
|
|
67
|
+
/** Mark a schema optional: `undefined` validates, and object keys become non-required. */
|
|
68
|
+
readonly optional: <T>(inner: Schema<T>) => OptionalSchema<T>;
|
|
69
|
+
};
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@infinityi/engine-lib/schema` — the schema contract used to describe and validate
|
|
3
|
+
* tool parameters and structured outputs.
|
|
4
|
+
*
|
|
5
|
+
* Providers read `Schema.jsonSchema`; the runtime calls `Schema.parse` to
|
|
6
|
+
* validate model-supplied arguments at the boundary.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
export { s } from "./builder";
|
|
11
|
+
export { asSchema, fromJsonSchema, toJsonSchema } from "./json-schema";
|
|
12
|
+
export { validateJsonSchema } from "./validate";
|
|
13
|
+
export type { Infer, JsonSchema, OptionalSchema, SafeParseResult, Schema, SchemaIssue, } from "./types";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for moving between {@link Schema} and raw {@link JsonSchema}.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { JsonSchema, Schema } from "./types";
|
|
7
|
+
/** Return the provider-facing {@link JsonSchema} for a schema. */
|
|
8
|
+
export declare function toJsonSchema<T>(schema: Schema<T>): JsonSchema;
|
|
9
|
+
/**
|
|
10
|
+
* Adapt an external schema implementation (e.g. a Zod adapter) into the
|
|
11
|
+
* engine-lib {@link Schema} contract. Only `jsonSchema` and `parse` are
|
|
12
|
+
* required; `safeParse` is derived if absent.
|
|
13
|
+
*/
|
|
14
|
+
export declare function asSchema<T>(impl: Pick<Schema<T>, "jsonSchema" | "parse"> & Partial<Pick<Schema<T>, "safeParse">>): Schema<T>;
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a raw {@link JsonSchema} as a {@link Schema}. Validation uses the
|
|
17
|
+
* built-in validator; the output type is supplied by the caller (`T`).
|
|
18
|
+
*/
|
|
19
|
+
export declare function fromJsonSchema<T = unknown>(jsonSchema: JsonSchema): Schema<T>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for the `@infinityi/engine-lib` schema layer.
|
|
3
|
+
*
|
|
4
|
+
* The {@link Schema} contract is the seam between engine-lib and LLM
|
|
5
|
+
* providers: providers read `.jsonSchema` (to advertise tool parameters /
|
|
6
|
+
* structured outputs), while the runtime calls `.parse` or `.safeParse` to
|
|
7
|
+
* validate model-supplied arguments at the boundary.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { SchemaIssue, SchemaValidationError } from "../errors";
|
|
12
|
+
/**
|
|
13
|
+
* A structural subset of JSON Schema (draft 2020-12) sufficient to describe
|
|
14
|
+
* tool parameters and structured outputs for every supported provider.
|
|
15
|
+
* Intentionally minimal and extensible; unsupported JSON Schema keywords are
|
|
16
|
+
* outside the stable validation contract.
|
|
17
|
+
*/
|
|
18
|
+
export interface JsonSchema {
|
|
19
|
+
type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
|
|
20
|
+
description?: string;
|
|
21
|
+
/** Object: property schemas. */
|
|
22
|
+
properties?: Record<string, JsonSchema>;
|
|
23
|
+
/** Object: required property names. */
|
|
24
|
+
required?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Object: whether unknown properties are permitted. Builders created with
|
|
27
|
+
* `s.object()` set this to `false`, making tool arguments strict by default.
|
|
28
|
+
*/
|
|
29
|
+
additionalProperties?: boolean;
|
|
30
|
+
/** Array: element schema. */
|
|
31
|
+
items?: JsonSchema;
|
|
32
|
+
/** Enumerated allowed values. */
|
|
33
|
+
enum?: ReadonlyArray<string | number>;
|
|
34
|
+
}
|
|
35
|
+
/** Result of a non-throwing parse. */
|
|
36
|
+
export type SafeParseResult<T> = {
|
|
37
|
+
success: true;
|
|
38
|
+
data: T;
|
|
39
|
+
} | {
|
|
40
|
+
success: false;
|
|
41
|
+
error: SchemaValidationError;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The engine-lib schema contract. A `Schema<T>` couples a provider-facing
|
|
45
|
+
* {@link JsonSchema} with runtime validation that yields a typed `T`.
|
|
46
|
+
*
|
|
47
|
+
* The stable surface is intentionally small: `jsonSchema`, `parse`,
|
|
48
|
+
* `safeParse`, and the type-only `_output` marker used by {@link Infer}.
|
|
49
|
+
*/
|
|
50
|
+
export interface Schema<T> {
|
|
51
|
+
/** Provider-facing JSON Schema (consumed by provider adapters in Phase 2+). */
|
|
52
|
+
readonly jsonSchema: JsonSchema;
|
|
53
|
+
/** Validate and return `T`, or throw {@link SchemaValidationError}. */
|
|
54
|
+
parse(input: unknown): T;
|
|
55
|
+
/** Validate without throwing. */
|
|
56
|
+
safeParse(input: unknown): SafeParseResult<T>;
|
|
57
|
+
/** Phantom marker carrying the output type for {@link Infer}. Never present at runtime. */
|
|
58
|
+
readonly _output?: T;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* A schema marked optional by `s.optional`. The `__optional` marker is a
|
|
62
|
+
* phantom (never present at runtime) used purely to make the corresponding
|
|
63
|
+
* object key optional in {@link Infer}.
|
|
64
|
+
*/
|
|
65
|
+
export interface OptionalSchema<T> extends Schema<T | undefined> {
|
|
66
|
+
readonly __optional: true;
|
|
67
|
+
}
|
|
68
|
+
/** Infer the TypeScript type carried by a {@link Schema}. */
|
|
69
|
+
export type Infer<S> = S extends Schema<infer T> ? T : never;
|
|
70
|
+
export type { SchemaIssue };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursive validator backing every {@link Schema}.
|
|
3
|
+
*
|
|
4
|
+
* Validation is driven entirely by a {@link JsonSchema} node so that the
|
|
5
|
+
* same logic covers both the built-in `s` builder and externally-supplied
|
|
6
|
+
* schemas adapted via `asSchema`. It collects *all* issues (rather than
|
|
7
|
+
* failing on the first) so callers get a complete picture.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { SchemaIssue } from "../errors";
|
|
12
|
+
import type { JsonSchema } from "./types";
|
|
13
|
+
type Path = ReadonlyArray<string | number>;
|
|
14
|
+
/**
|
|
15
|
+
* Validate `input` against a {@link JsonSchema} node, accumulating issues.
|
|
16
|
+
* Returns an empty array when `input` is valid.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateJsonSchema(node: JsonSchema, input: unknown, path?: Path): SchemaIssue[];
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@infinityi/engine-lib/session` — durable conversation state: the {@link SessionStore}
|
|
3
|
+
* persistence contract, the built-in {@link InMemorySessionStore}, and the
|
|
4
|
+
* {@link createSession} handle threaded into a run.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
export { createSession } from "./session";
|
|
9
|
+
export type { CreateSessionOptions } from "./session";
|
|
10
|
+
export { InMemorySessionStore } from "./store";
|
|
11
|
+
export type { Session, SessionState, SessionStore } from "./types";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {@link createSession} — the synchronous factory for a {@link Session} handle.
|
|
3
|
+
*
|
|
4
|
+
* Construction never performs I/O: the underlying {@link SessionStore} is consulted
|
|
5
|
+
* lazily on the first {@link Session.messages} / {@link Session.append} call. When a
|
|
6
|
+
* store already holds history for the id, that history is resumed; otherwise any
|
|
7
|
+
* `messages` seed is written through on first access.
|
|
8
|
+
*
|
|
9
|
+
* `runAgent` appends to a session only after a successful run. Instructions and
|
|
10
|
+
* injected context are request-time system messages and are never persisted.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { Message } from "../messages/types";
|
|
15
|
+
import type { Session, SessionStore } from "./types";
|
|
16
|
+
/** Options for {@link createSession}. */
|
|
17
|
+
export interface CreateSessionOptions {
|
|
18
|
+
/** Stable id; when omitted a random id is generated. */
|
|
19
|
+
readonly id?: string;
|
|
20
|
+
/** Backing store; defaults to a fresh {@link InMemorySessionStore}. */
|
|
21
|
+
readonly store?: SessionStore;
|
|
22
|
+
/** Seed history, written through only once and only if the store has no history for this id. */
|
|
23
|
+
readonly messages?: readonly Message[];
|
|
24
|
+
/** Free-form metadata attached to the session handle. */
|
|
25
|
+
readonly metadata?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create a {@link Session} handle. Synchronous: the store is read on first use,
|
|
29
|
+
* so an existing conversation is resumed by passing its `id`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createSession(opts?: CreateSessionOptions): Session;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory {@link SessionStore} — the default, deterministic persistence double.
|
|
3
|
+
*
|
|
4
|
+
* Holds each session's history in a `Map`, copying message arrays on the way in
|
|
5
|
+
* and out so callers cannot mutate stored state by reference. Suitable for tests
|
|
6
|
+
* and ephemeral (single-process) runs; swap in a durable store for persistence
|
|
7
|
+
* across restarts.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import type { Message } from "../messages/types";
|
|
12
|
+
import type { SessionState, SessionStore } from "./types";
|
|
13
|
+
/** A process-local {@link SessionStore} backed by a `Map`. */
|
|
14
|
+
export declare class InMemorySessionStore implements SessionStore {
|
|
15
|
+
private readonly entries;
|
|
16
|
+
load(id: string): Promise<SessionState | undefined>;
|
|
17
|
+
append(id: string, messages: readonly Message[]): Promise<void>;
|
|
18
|
+
save(state: SessionState): Promise<void>;
|
|
19
|
+
delete(id: string): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable conversation state.
|
|
3
|
+
*
|
|
4
|
+
* A {@link SessionStore} is the pluggable persistence seam (an in-memory double
|
|
5
|
+
* ships built-in); a {@link Session} is the per-conversation handle threaded into
|
|
6
|
+
* a run. History is read before a run and appended after it. Only the *conversation*
|
|
7
|
+
* (user input + produced assistant/tool messages) is persisted — the run-time
|
|
8
|
+
* system/instruction and injected-context messages are rebuilt fresh every run and
|
|
9
|
+
* are never stored.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { Message } from "../messages/types";
|
|
14
|
+
/** Ordered, durable conversation state keyed by id. */
|
|
15
|
+
export interface SessionState {
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly messages: readonly Message[];
|
|
18
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Pluggable persistence for session history.
|
|
22
|
+
*
|
|
23
|
+
* Implementations must preserve message order, treat {@link append} as an
|
|
24
|
+
* atomic add to the tail, and return snapshots that callers cannot mutate to
|
|
25
|
+
* alter stored history by reference. The built-in {@link InMemorySessionStore}
|
|
26
|
+
* is the reference double; a `forge/data`-backed store can be layered on later
|
|
27
|
+
* behind this same contract.
|
|
28
|
+
*/
|
|
29
|
+
export interface SessionStore {
|
|
30
|
+
/** Load the full state for `id`, or `undefined` if none exists yet. */
|
|
31
|
+
load(id: string): Promise<SessionState | undefined>;
|
|
32
|
+
/** Append `messages` to the tail of `id`'s history (creating it if absent). */
|
|
33
|
+
append(id: string, messages: readonly Message[]): Promise<void>;
|
|
34
|
+
/** Replace the full state for `state.id`. */
|
|
35
|
+
save(state: SessionState): Promise<void>;
|
|
36
|
+
/** Remove all history for `id` (no-op if absent). */
|
|
37
|
+
delete(id: string): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A per-conversation handle passed to `runAgent`.
|
|
41
|
+
*
|
|
42
|
+
* Created synchronously by {@link createSession}; history is resolved lazily
|
|
43
|
+
* (on the first {@link Session.messages}, {@link Session.append}, or
|
|
44
|
+
* {@link Session.clear} call) so construction never blocks on I/O.
|
|
45
|
+
*/
|
|
46
|
+
export interface Session {
|
|
47
|
+
readonly id: string;
|
|
48
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
49
|
+
/** Snapshot of the current ordered history. */
|
|
50
|
+
messages(): Promise<Message[]>;
|
|
51
|
+
/** Append messages to the conversation and persist them. */
|
|
52
|
+
append(messages: readonly Message[]): Promise<void>;
|
|
53
|
+
/** Drop all history for this session. */
|
|
54
|
+
clear(): Promise<void>;
|
|
55
|
+
}
|