liminal 0.5.14 → 0.5.15
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/CHANGELOG.md +6 -0
- package/Context.ts +21 -4
- package/Definition.ts +16 -0
- package/L/L.ts +0 -1
- package/L/all.ts +4 -0
- package/L/assistant.ts +4 -0
- package/L/catch.ts +4 -0
- package/L/continuation.ts +3 -2
- package/L/emit.ts +6 -2
- package/L/infer.ts +16 -10
- package/L/message.ts +4 -0
- package/L/model.ts +4 -0
- package/L/reflect.ts +2 -1
- package/L/run.ts +1 -0
- package/L/strand.ts +6 -2
- package/L/stream.ts +2 -1
- package/Model.ts +4 -4
- package/ModelRegistry.ts +16 -3
- package/Rune.ts +36 -7
- package/Strand.ts +37 -6
- package/dist/Context.d.ts +19 -0
- package/dist/Context.js +7 -2
- package/dist/Context.js.map +1 -1
- package/dist/Definition.d.ts +14 -0
- package/dist/Definition.js +11 -0
- package/dist/Definition.js.map +1 -1
- package/dist/L/L.d.ts +0 -1
- package/dist/L/L.js +0 -1
- package/dist/L/L.js.map +1 -1
- package/dist/L/all.d.ts +4 -0
- package/dist/L/all.js.map +1 -1
- package/dist/L/assistant.d.ts +4 -0
- package/dist/L/assistant.js.map +1 -1
- package/dist/L/catch.d.ts +4 -0
- package/dist/L/catch.js +4 -0
- package/dist/L/catch.js.map +1 -1
- package/dist/L/continuation.d.ts +1 -0
- package/dist/L/continuation.js +3 -2
- package/dist/L/continuation.js.map +1 -1
- package/dist/L/emit.d.ts +4 -0
- package/dist/L/emit.js +6 -2
- package/dist/L/emit.js.map +1 -1
- package/dist/L/infer.d.ts +4 -0
- package/dist/L/infer.js +9 -5
- package/dist/L/infer.js.map +1 -1
- package/dist/L/message.d.ts +4 -0
- package/dist/L/message.js +4 -0
- package/dist/L/message.js.map +1 -1
- package/dist/L/model.d.ts +4 -0
- package/dist/L/model.js +4 -0
- package/dist/L/model.js.map +1 -1
- package/dist/L/reflect.d.ts +1 -0
- package/dist/L/reflect.js +2 -1
- package/dist/L/reflect.js.map +1 -1
- package/dist/L/run.d.ts +1 -0
- package/dist/L/run.js.map +1 -1
- package/dist/L/strand.d.ts +4 -0
- package/dist/L/strand.js +6 -2
- package/dist/L/strand.js.map +1 -1
- package/dist/L/stream.d.ts +1 -0
- package/dist/L/stream.js +2 -1
- package/dist/L/stream.js.map +1 -1
- package/dist/Model.d.ts +4 -4
- package/dist/Model.js +4 -4
- package/dist/ModelRegistry.d.ts +11 -1
- package/dist/ModelRegistry.js +16 -3
- package/dist/ModelRegistry.js.map +1 -1
- package/dist/Rune.d.ts +29 -8
- package/dist/Rune.js +2 -0
- package/dist/Rune.js.map +1 -1
- package/dist/Strand.d.ts +24 -0
- package/dist/Strand.js +27 -4
- package/dist/Strand.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util/JSONValue.d.ts +1 -1
- package/dist/util/JSONValue.js +21 -9
- package/dist/util/JSONValue.js.map +1 -1
- package/package.json +1 -1
- package/util/JSONValue.ts +23 -8
- package/L/context.ts +0 -12
- package/dist/L/context.d.ts +0 -2
- package/dist/L/context.js +0 -12
- package/dist/L/context.js.map +0 -1
package/CHANGELOG.md
CHANGED
package/Context.ts
CHANGED
|
@@ -3,22 +3,39 @@ import type { Message } from "./Message.ts"
|
|
|
3
3
|
import { ModelRegistry } from "./ModelRegistry.ts"
|
|
4
4
|
import type { Tool } from "./Tool.ts"
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Context represents the execution environment for a Strand.
|
|
8
|
+
*
|
|
9
|
+
* It holds all the stateful components needed during strand execution:
|
|
10
|
+
* - Message history.
|
|
11
|
+
* - Event handler for processing events.
|
|
12
|
+
* - Model registry for tracking available language models.
|
|
13
|
+
* - Available tools for model-driven function calling.
|
|
14
|
+
*/
|
|
6
15
|
export interface Context {
|
|
16
|
+
/** Event handler for processing events during strand execution. */
|
|
7
17
|
readonly handler: Handler | undefined
|
|
18
|
+
/** Registry of available models for inference. */
|
|
8
19
|
readonly models: ModelRegistry
|
|
20
|
+
/** Accumulated message history. */
|
|
9
21
|
readonly messages: Array<Message>
|
|
22
|
+
/** Set of tools available to the models. */
|
|
10
23
|
readonly tools: Set<Tool>
|
|
11
|
-
|
|
24
|
+
/** Creates a copy of the current `Context` for child strands. */
|
|
12
25
|
clone(): Context
|
|
13
26
|
}
|
|
14
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Factory function to create a new Context.
|
|
30
|
+
* @param context Optional base context from which to initialize.
|
|
31
|
+
* @returns A newly created Context.
|
|
32
|
+
*/
|
|
15
33
|
export function Context(context?: Omit<Context, "clone">): Context {
|
|
16
34
|
return {
|
|
17
35
|
handler: context?.handler,
|
|
18
|
-
models: context?.models
|
|
19
|
-
messages: [],
|
|
36
|
+
models: context?.models?.clone() ?? new ModelRegistry(),
|
|
37
|
+
messages: [...(context?.messages ?? [])],
|
|
20
38
|
tools: new Set(context?.tools),
|
|
21
|
-
|
|
22
39
|
clone(): Context {
|
|
23
40
|
return {
|
|
24
41
|
handler: this.handler,
|
package/Definition.ts
CHANGED
|
@@ -1,22 +1,38 @@
|
|
|
1
1
|
import type { Rune } from "./Rune.ts"
|
|
2
2
|
|
|
3
3
|
export type RuneIterator<Y extends Rune<any> = Rune<any>, T = any> = Iterator<Y, T> | AsyncIterator<Y, T>
|
|
4
|
+
|
|
4
5
|
export type RuneIterable<Y extends Rune<any> = Rune<any>, T = any> = Iterable<Y, T> | AsyncIterable<Y, T>
|
|
6
|
+
|
|
5
7
|
export type Definition<Y extends Rune<any> = Rune<any>, T = any> = RuneIterable<Y, T> | (() => RuneIterable<Y, T>)
|
|
6
8
|
|
|
7
9
|
export namespace Definition {
|
|
10
|
+
/** Extracts the Rune type from a Definition. */
|
|
8
11
|
export type Y<X extends Definition> = X extends RuneIterable<infer Y> ? Y
|
|
9
12
|
: X extends () => RuneIterable<infer Y> ? Y
|
|
10
13
|
: X extends RuneIterator<infer Y> ? Y
|
|
11
14
|
: never
|
|
12
15
|
|
|
16
|
+
/** Extracts the result type from a Definition. */
|
|
13
17
|
export type T<X extends Definition> = X extends RuneIterable<Rune<any>, infer T> ? T
|
|
14
18
|
: X extends () => RuneIterable<Rune<any>, infer T> ? T
|
|
15
19
|
: X extends RuneIterator<Rune<any>, infer T> ? T
|
|
16
20
|
: never
|
|
17
21
|
|
|
22
|
+
/** Extracts the event type from a Definition. */
|
|
18
23
|
export type E<X extends Definition> = Rune.E<Y<X>>
|
|
19
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Converts a Definition into a RuneIterator.
|
|
27
|
+
*
|
|
28
|
+
* This function handles all the different forms a Definition can take:
|
|
29
|
+
* - Synchronous iterables
|
|
30
|
+
* - Asynchronous iterables
|
|
31
|
+
* - Factory functions returning iterables
|
|
32
|
+
*
|
|
33
|
+
* @param definition The definition to unwrap.
|
|
34
|
+
* @returns A RuneIterator ready for consumption.
|
|
35
|
+
*/
|
|
20
36
|
export function unwrap<Y extends Rune<any>, T>(definition: Definition<Y, T>): RuneIterator<Y, T> {
|
|
21
37
|
if (Symbol.iterator in definition) {
|
|
22
38
|
return definition[Symbol.iterator]()
|
package/L/L.ts
CHANGED
package/L/all.ts
CHANGED
|
@@ -6,6 +6,10 @@ import { Strand } from "../Strand.ts"
|
|
|
6
6
|
import { continuation } from "./continuation.ts"
|
|
7
7
|
import { reflect } from "./reflect.ts"
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Runs multiple definitions in parallel and collects their results.
|
|
11
|
+
* Can be used with an array or object of definitions.
|
|
12
|
+
*/
|
|
9
13
|
export function all<A extends Array<Definition>>(
|
|
10
14
|
definitions: A,
|
|
11
15
|
context?: Context,
|
package/L/assistant.ts
CHANGED
|
@@ -4,6 +4,10 @@ import { Schema } from "../Schema.ts"
|
|
|
4
4
|
import { infer } from "./infer.ts"
|
|
5
5
|
import { message } from "./message.ts"
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Produces an assistant message when yielded. Can be called with a schema
|
|
9
|
+
* for structured output. Otherwise produces a string.
|
|
10
|
+
*/
|
|
7
11
|
export interface assistant extends Iterable<Rune<LEvent>, string> {
|
|
8
12
|
<T>(schema: Schema<T>): Generator<Rune<LEvent>, T>
|
|
9
13
|
}
|
package/L/catch.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { reflect } from "./reflect.ts"
|
|
|
7
7
|
|
|
8
8
|
export { catch_ as catch }
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Error handling utility that catches exceptions from running a definition.
|
|
12
|
+
* Returns a result object indicating whether the operation succeeded or failed.
|
|
13
|
+
*/
|
|
10
14
|
function* catch_<Y extends Rune<any>, T>(
|
|
11
15
|
definition: Definition<Y, T>,
|
|
12
16
|
): Generator<Rune<LEvent> | Rune<Y>, CatchResult<T>> {
|
package/L/continuation.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { LEvent } from "../LEvent.ts"
|
|
2
2
|
import { Rune, RuneKey } from "../Rune.ts"
|
|
3
3
|
|
|
4
|
+
/** Yields a continuation rune that executes a function and passes its result to the next iteration. */
|
|
4
5
|
export function* continuation<R>(debug: string, f: () => R): Generator<Rune<LEvent>, Awaited<R>> {
|
|
5
6
|
return yield {
|
|
6
7
|
[RuneKey]: true,
|
|
7
|
-
|
|
8
|
-
kind: "
|
|
8
|
+
instruction: {
|
|
9
|
+
kind: "continue",
|
|
9
10
|
debug,
|
|
10
11
|
f,
|
|
11
12
|
},
|
package/L/emit.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { Rune, RuneKey } from "../Rune.ts"
|
|
2
2
|
import type { EnsureNarrow } from "../util/EnsureNarrow.ts"
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Emits an event to be supplied to handlers.
|
|
6
|
+
* Used for broadcasting state changes and triggering side effects.
|
|
7
|
+
*/
|
|
4
8
|
export function* emit<E>(event: EnsureNarrow<E>): Generator<Rune<E>, void> {
|
|
5
9
|
return yield {
|
|
6
10
|
[RuneKey]: true,
|
|
7
|
-
|
|
8
|
-
kind: "
|
|
11
|
+
instruction: {
|
|
12
|
+
kind: "emit",
|
|
9
13
|
event,
|
|
10
14
|
},
|
|
11
15
|
}
|
package/L/infer.ts
CHANGED
|
@@ -6,22 +6,28 @@ import { continuation } from "./continuation.ts"
|
|
|
6
6
|
import { emit } from "./emit.ts"
|
|
7
7
|
import { reflect } from "./reflect.ts"
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Requests an inference from the current model, optionally with a schema.
|
|
11
|
+
* Emits inference-related events and returns the model's response as a string.
|
|
12
|
+
*/
|
|
9
13
|
export function* infer(schema?: Schema): Generator<Rune<LEvent>, string> {
|
|
10
14
|
const { context: { models, messages }, signal } = yield* reflect
|
|
11
15
|
const model = models.peek()
|
|
12
16
|
LiminalAssertionError.assert(model)
|
|
13
17
|
const requestId = crypto.randomUUID()
|
|
14
18
|
yield* emit(new InferenceRequested(requestId, schema))
|
|
15
|
-
let inference = yield* continuation(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
: Schema.wrap(schema),
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
let inference = yield* continuation(
|
|
20
|
+
"infer",
|
|
21
|
+
model
|
|
22
|
+
.seal({
|
|
23
|
+
messages,
|
|
24
|
+
...schema && {
|
|
25
|
+
schema: schema.type === "object" ? schema : Schema.wrap(schema),
|
|
26
|
+
},
|
|
27
|
+
signal,
|
|
28
|
+
})
|
|
29
|
+
.resolve,
|
|
30
|
+
)
|
|
25
31
|
if (schema?.type && schema.type !== "object") {
|
|
26
32
|
inference = JSON.stringify(JSON.parse(inference).value)
|
|
27
33
|
}
|
package/L/message.ts
CHANGED
|
@@ -4,6 +4,10 @@ import type { Rune } from "../Rune.ts"
|
|
|
4
4
|
import { emit } from "./emit.ts"
|
|
5
5
|
import { reflect } from "./reflect.ts"
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Adds a new message to the current context's message list.
|
|
9
|
+
* Emits a message append event to observers.
|
|
10
|
+
*/
|
|
7
11
|
export function* message(role: MessageRole, content: Array<Content>): Generator<Rune<LEvent>, void> {
|
|
8
12
|
const { context: { messages } } = yield* reflect
|
|
9
13
|
const message: Message = { role, parts: content }
|
package/L/model.ts
CHANGED
|
@@ -5,6 +5,10 @@ import type { Rune } from "../Rune.ts"
|
|
|
5
5
|
import { emit } from "./emit.ts"
|
|
6
6
|
import { reflect } from "./reflect.ts"
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Registers a model in the current context and emits a model registration event.
|
|
10
|
+
* Returns the registered model instance.
|
|
11
|
+
*/
|
|
8
12
|
export function* model(model: Model): Generator<Rune<LEvent>, Model> {
|
|
9
13
|
const { context: { models } } = yield* reflect
|
|
10
14
|
models.register(model)
|
package/L/reflect.ts
CHANGED
|
@@ -2,11 +2,12 @@ import type { LEvent } from "../LEvent.ts"
|
|
|
2
2
|
import { Rune, RuneKey } from "../Rune.ts"
|
|
3
3
|
import type { Strand } from "../Strand.ts"
|
|
4
4
|
|
|
5
|
+
/** Returns the current strand instance, providing access to context and parent information. */
|
|
5
6
|
export const reflect: Iterable<Rune<LEvent>, Strand> = {
|
|
6
7
|
*[Symbol.iterator]() {
|
|
7
8
|
return yield {
|
|
8
9
|
[RuneKey]: true,
|
|
9
|
-
|
|
10
|
+
instruction: { kind: "reflect" },
|
|
10
11
|
}
|
|
11
12
|
},
|
|
12
13
|
}
|
package/L/run.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type { Rune } from "../Rune.ts"
|
|
|
7
7
|
import { Strand } from "../Strand.ts"
|
|
8
8
|
import type { Tool } from "../Tool.ts"
|
|
9
9
|
|
|
10
|
+
/** Configuration options for running a definition. */
|
|
10
11
|
export interface RunConfig<Y extends Rune<any>> {
|
|
11
12
|
handler?: Handler<Y> | undefined
|
|
12
13
|
models?: ModelRegistry | undefined
|
package/L/strand.ts
CHANGED
|
@@ -3,14 +3,18 @@ import type { Definition } from "../Definition.ts"
|
|
|
3
3
|
import type { LEvent } from "../LEvent.ts"
|
|
4
4
|
import { type Rune, RuneKey } from "../Rune.ts"
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Creates a child strand that executes a definition.
|
|
8
|
+
* Optionally specify the context. Otherwise the current context is inherited.
|
|
9
|
+
*/
|
|
6
10
|
export function* strand<Y extends Rune<any>, T>(
|
|
7
11
|
definition: Definition<Y, T>,
|
|
8
12
|
context?: Context,
|
|
9
13
|
): Generator<Rune<LEvent>, T> {
|
|
10
14
|
return yield {
|
|
11
15
|
[RuneKey]: true,
|
|
12
|
-
|
|
13
|
-
kind: "
|
|
16
|
+
instruction: {
|
|
17
|
+
kind: "create_child",
|
|
14
18
|
definition,
|
|
15
19
|
context,
|
|
16
20
|
},
|
package/L/stream.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { continuation } from "./continuation.ts"
|
|
|
5
5
|
import { emit } from "./emit.ts"
|
|
6
6
|
import { reflect } from "./reflect.ts"
|
|
7
7
|
|
|
8
|
+
/** Creates a readable stream of content from the current model. */
|
|
8
9
|
export const stream: Iterable<Rune<LEvent>, ReadableStream<string>> = {
|
|
9
10
|
*[Symbol.iterator]() {
|
|
10
11
|
const { context: { models, messages }, signal } = yield* reflect
|
|
@@ -12,6 +13,6 @@ export const stream: Iterable<Rune<LEvent>, ReadableStream<string>> = {
|
|
|
12
13
|
LiminalAssertionError.assert(model)
|
|
13
14
|
const requestId = crypto.randomUUID()
|
|
14
15
|
yield* emit(new InferenceRequested(requestId))
|
|
15
|
-
return yield* continuation("stream",
|
|
16
|
+
return yield* continuation("stream", model.seal({ messages, signal }).stream)
|
|
16
17
|
},
|
|
17
18
|
}
|
package/Model.ts
CHANGED
|
@@ -5,12 +5,12 @@ import { attachCustomInspect } from "./util/attachCustomInspect.ts"
|
|
|
5
5
|
|
|
6
6
|
export class Model {
|
|
7
7
|
constructor(
|
|
8
|
-
readonly
|
|
8
|
+
readonly client: string,
|
|
9
9
|
readonly seal: (envelope: Envelope) => SealedEnvelope,
|
|
10
10
|
) {}
|
|
11
11
|
|
|
12
12
|
static {
|
|
13
|
-
attachCustomInspect(this, ({
|
|
13
|
+
attachCustomInspect(this, ({ client }) => ({ client }))
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -22,6 +22,6 @@ export interface Envelope {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export interface SealedEnvelope {
|
|
25
|
-
resolve()
|
|
26
|
-
stream()
|
|
25
|
+
resolve: () => Promise<string>
|
|
26
|
+
stream: () => ReadableStream<string>
|
|
27
27
|
}
|
package/ModelRegistry.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import type { Model } from "./Model.ts"
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* An intrusive doubly-linked list for storing `Model`s.
|
|
5
|
+
* Provides efficient insertion, removal, and lookups.
|
|
6
|
+
*/
|
|
4
7
|
export class ModelRegistry {
|
|
5
8
|
declare head?: ModelRegistryNode | undefined
|
|
6
9
|
declare tail?: ModelRegistryNode | undefined
|
|
7
10
|
|
|
11
|
+
/** Returns the most recently registered model */
|
|
8
12
|
peek() {
|
|
9
13
|
return this.tail?.model
|
|
10
14
|
}
|
|
11
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Registers a new model and returns the created node
|
|
18
|
+
* @param value The model to register
|
|
19
|
+
*/
|
|
12
20
|
register(value: Model): ModelRegistryNode {
|
|
13
21
|
const node: ModelRegistryNode = {
|
|
14
22
|
prev: this.tail,
|
|
@@ -23,6 +31,7 @@ export class ModelRegistry {
|
|
|
23
31
|
return node
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
/** Remove a model from the registry. */
|
|
26
35
|
remove(node: ModelRegistryNode) {
|
|
27
36
|
if (node.prev) {
|
|
28
37
|
node.prev.next = node.next
|
|
@@ -36,13 +45,17 @@ export class ModelRegistry {
|
|
|
36
45
|
if (node === this.tail) {
|
|
37
46
|
this.tail = node.prev
|
|
38
47
|
}
|
|
39
|
-
node.prev =
|
|
48
|
+
node.prev = undefined
|
|
49
|
+
delete node.next
|
|
40
50
|
}
|
|
41
51
|
|
|
52
|
+
/** Creates a deep copy of this registry. */
|
|
42
53
|
clone() {
|
|
43
54
|
const instance = new ModelRegistry()
|
|
44
55
|
for (let node = this.head; node; node = node.next) {
|
|
45
|
-
|
|
56
|
+
if (node.model) {
|
|
57
|
+
instance.register(node.model)
|
|
58
|
+
}
|
|
46
59
|
}
|
|
47
60
|
return instance
|
|
48
61
|
}
|
package/Rune.ts
CHANGED
|
@@ -1,31 +1,60 @@
|
|
|
1
1
|
import type { Context } from "./Context.ts"
|
|
2
2
|
import type { Definition } from "./Definition.ts"
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* `Rune` represents a computational unit within a Strand execution.
|
|
6
|
+
* It is a specialized protocol for expressing different kinds of operations
|
|
7
|
+
* that can be yielded from generator functions to control message state
|
|
8
|
+
* and concurrency within the Liminal runtime.
|
|
9
|
+
* @template E The event type this Rune can handle
|
|
10
|
+
*/
|
|
4
11
|
export interface Rune<E> {
|
|
5
12
|
[RuneKey]: true
|
|
6
|
-
|
|
7
|
-
|
|
13
|
+
instruction: RuneInstruction<E>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type RuneInstruction<E> =
|
|
17
|
+
| RuneInstruction.Continue
|
|
18
|
+
| RuneInstruction.Emit<E>
|
|
19
|
+
| RuneInstruction.Reflect
|
|
20
|
+
| RuneInstruction.CreateChild
|
|
21
|
+
export namespace RuneInstruction {
|
|
22
|
+
/** Tells the runtime to call this function and and pass the result to the next iteration. */
|
|
23
|
+
export interface Continue {
|
|
24
|
+
kind: "continue"
|
|
8
25
|
debug: string
|
|
9
26
|
f: () => any
|
|
10
|
-
}
|
|
11
|
-
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Dispatch an event to the registered handler. */
|
|
30
|
+
export interface Emit<E> {
|
|
31
|
+
kind: "emit"
|
|
12
32
|
event: E
|
|
13
|
-
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Tells the runtime to provide a reference to the current strand */
|
|
36
|
+
export interface Reflect {
|
|
14
37
|
kind: "reflect"
|
|
15
|
-
}
|
|
16
|
-
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Creates a nested execution context with its own definition. */
|
|
41
|
+
export interface CreateChild {
|
|
42
|
+
kind: "create_child"
|
|
17
43
|
definition: Definition
|
|
18
44
|
context?: Context | undefined
|
|
19
45
|
}
|
|
20
46
|
}
|
|
21
47
|
|
|
22
48
|
export namespace Rune {
|
|
49
|
+
/** Extract the event type from a Rune type. */
|
|
23
50
|
export type E<X extends Rune<any>> = X extends Rune<infer E> ? E : never
|
|
24
51
|
|
|
52
|
+
/** Type guard to check if a value is a Rune. */
|
|
25
53
|
export function is(value: unknown): value is Rune<any> {
|
|
26
54
|
return typeof value === "object" && value !== null && RuneKey in value
|
|
27
55
|
}
|
|
28
56
|
}
|
|
29
57
|
|
|
58
|
+
/** Symbol used to identify Rune objects. */
|
|
30
59
|
export const RuneKey: unique symbol = Symbol.for("liminal/RuneKey")
|
|
31
60
|
export type RuneKey = typeof RuneKey
|
package/Strand.ts
CHANGED
|
@@ -6,26 +6,53 @@ import { StrandStatusChanged } from "./LEvent.ts"
|
|
|
6
6
|
import type { Rune } from "./Rune.ts"
|
|
7
7
|
import { attachCustomInspect } from "./util/attachCustomInspect.ts"
|
|
8
8
|
|
|
9
|
+
/** Configuration options for creating a new Strand. */
|
|
9
10
|
export interface StrandConfig {
|
|
11
|
+
/** Optional parent strand that this strand will be a child of */
|
|
10
12
|
parent?: Strand | undefined
|
|
13
|
+
/** Optional context for the strand execution */
|
|
11
14
|
context?: Context | undefined
|
|
15
|
+
/** Optional abort signal that can be used to cancel strand execution */
|
|
12
16
|
signal?: AbortSignal | undefined
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
let nextIndex: number = 0
|
|
16
20
|
|
|
21
|
+
/**
|
|
22
|
+
* A "Strand" is the core unit of execution in Liminal.
|
|
23
|
+
*
|
|
24
|
+
* It represents a suspendable computation that can yield Runes to control conversation state.
|
|
25
|
+
* Strands implement both the Iterable and PromiseLike interfaces to enable both
|
|
26
|
+
* running (via awaiting) and joining to parent strands (via yielding).
|
|
27
|
+
*
|
|
28
|
+
* Strands maintain their own state and can be hierarchically organized with parent-child
|
|
29
|
+
* relationships. Child strands are bound to their parents, ensuring consistent
|
|
30
|
+
* cancellation behavior.
|
|
31
|
+
*
|
|
32
|
+
* @template Y The type of Runes this Strand can yield.
|
|
33
|
+
* @template T The result type of the Strand.
|
|
34
|
+
*/
|
|
17
35
|
export class Strand<Y extends Rune<any> = Rune<any>, T = any> implements Iterable<Y, T>, PromiseLike<T> {
|
|
18
36
|
declare T: T
|
|
19
37
|
declare Y: Y
|
|
20
38
|
|
|
39
|
+
/** Controls abort signal propagation. */
|
|
21
40
|
readonly #controller: AbortController = new AbortController()
|
|
41
|
+
/** Signal that can be used to detect when this strand is aborted. */
|
|
22
42
|
readonly signal: AbortSignal = this.#controller.signal
|
|
43
|
+
/** Optional event handler function. */
|
|
23
44
|
#handle?: ((this: Strand, event: any) => void) | undefined
|
|
45
|
+
/** The definition (usually via generator function) that powers this strand. */
|
|
24
46
|
#definition: Definition<Y, T>
|
|
47
|
+
/** Current status of the strand (untouched, pending, resolved, rejected) */
|
|
25
48
|
status: StrandStatus<T> = { type: "untouched" }
|
|
49
|
+
/** Unique identifier for this strand. */
|
|
26
50
|
readonly index: number = nextIndex++
|
|
51
|
+
/** Nesting depth in the strand hierarchy. */
|
|
27
52
|
readonly depth: number
|
|
53
|
+
/** The parent strand or undefined. */
|
|
28
54
|
declare readonly parent?: Strand
|
|
55
|
+
/** The conversation state with which the strand operates. */
|
|
29
56
|
readonly context: Context
|
|
30
57
|
|
|
31
58
|
constructor(definition: Definition<Y, T>, config: StrandConfig) {
|
|
@@ -123,22 +150,22 @@ export class Strand<Y extends Rune<any> = Rune<any>, T = any> implements Iterabl
|
|
|
123
150
|
let current = await iterator.next()
|
|
124
151
|
while (!current.done) {
|
|
125
152
|
const rune = current.value
|
|
126
|
-
const { value } = rune
|
|
153
|
+
const { instruction: value } = rune
|
|
127
154
|
switch (value.kind) {
|
|
128
155
|
case "reflect": {
|
|
129
156
|
nextArg = this
|
|
130
157
|
break
|
|
131
158
|
}
|
|
132
|
-
case "
|
|
159
|
+
case "continue": {
|
|
133
160
|
nextArg = await value.f()
|
|
134
161
|
break
|
|
135
162
|
}
|
|
136
|
-
case "
|
|
163
|
+
case "emit": {
|
|
137
164
|
this.#handle?.(value.event)
|
|
138
165
|
nextArg = undefined
|
|
139
166
|
break
|
|
140
167
|
}
|
|
141
|
-
case "
|
|
168
|
+
case "create_child": {
|
|
142
169
|
nextArg = await new Strand(value.definition, {
|
|
143
170
|
parent: this,
|
|
144
171
|
context: value.context ?? this.context.clone(),
|
|
@@ -185,6 +212,7 @@ export class Strand<Y extends Rune<any> = Rune<any>, T = any> implements Iterabl
|
|
|
185
212
|
case "config_signal_aborted":
|
|
186
213
|
case "parent_aborted":
|
|
187
214
|
case "continuation_exception_thrown":
|
|
215
|
+
// case "model_error":
|
|
188
216
|
case "handler_exception_thrown": {
|
|
189
217
|
return Promise.reject(new StrandRejectedError(status))
|
|
190
218
|
}
|
|
@@ -230,8 +258,6 @@ export namespace StrandStatus {
|
|
|
230
258
|
| Rejected.ContinuationExceptionThrown
|
|
231
259
|
| Rejected.HandlerExceptionThrown
|
|
232
260
|
// | Rejected.ModelError
|
|
233
|
-
// | Rejected.ValidationError
|
|
234
|
-
// | Rejected.Timeout
|
|
235
261
|
export namespace Rejected {
|
|
236
262
|
export interface ConfigSignalAborted {
|
|
237
263
|
type: "config_signal_aborted"
|
|
@@ -249,5 +275,10 @@ export namespace StrandStatus {
|
|
|
249
275
|
type: "handler_exception_thrown"
|
|
250
276
|
exception: unknown
|
|
251
277
|
}
|
|
278
|
+
// export interface ModelError {
|
|
279
|
+
// type: "model_error"
|
|
280
|
+
// model: string
|
|
281
|
+
// error: unknown
|
|
282
|
+
// }
|
|
252
283
|
}
|
|
253
284
|
}
|
package/dist/Context.d.ts
CHANGED
|
@@ -2,11 +2,30 @@ import type { Handler } from "./Handler.ts";
|
|
|
2
2
|
import type { Message } from "./Message.ts";
|
|
3
3
|
import { ModelRegistry } from "./ModelRegistry.ts";
|
|
4
4
|
import type { Tool } from "./Tool.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Context represents the execution environment for a Strand.
|
|
7
|
+
*
|
|
8
|
+
* It holds all the stateful components needed during strand execution:
|
|
9
|
+
* - Message history.
|
|
10
|
+
* - Event handler for processing events.
|
|
11
|
+
* - Model registry for tracking available language models.
|
|
12
|
+
* - Available tools for model-driven function calling.
|
|
13
|
+
*/
|
|
5
14
|
export interface Context {
|
|
15
|
+
/** Event handler for processing events during strand execution. */
|
|
6
16
|
readonly handler: Handler | undefined;
|
|
17
|
+
/** Registry of available models for inference. */
|
|
7
18
|
readonly models: ModelRegistry;
|
|
19
|
+
/** Accumulated message history. */
|
|
8
20
|
readonly messages: Array<Message>;
|
|
21
|
+
/** Set of tools available to the models. */
|
|
9
22
|
readonly tools: Set<Tool>;
|
|
23
|
+
/** Creates a copy of the current `Context` for child strands. */
|
|
10
24
|
clone(): Context;
|
|
11
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Factory function to create a new Context.
|
|
28
|
+
* @param context Optional base context from which to initialize.
|
|
29
|
+
* @returns A newly created Context.
|
|
30
|
+
*/
|
|
12
31
|
export declare function Context(context?: Omit<Context, "clone">): Context;
|
package/dist/Context.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { ModelRegistry } from "./ModelRegistry.js";
|
|
2
|
+
/**
|
|
3
|
+
* Factory function to create a new Context.
|
|
4
|
+
* @param context Optional base context from which to initialize.
|
|
5
|
+
* @returns A newly created Context.
|
|
6
|
+
*/
|
|
2
7
|
export function Context(context) {
|
|
3
8
|
return {
|
|
4
9
|
handler: context?.handler,
|
|
5
|
-
models: context?.models
|
|
6
|
-
messages: [],
|
|
10
|
+
models: context?.models?.clone() ?? new ModelRegistry(),
|
|
11
|
+
messages: [...(context?.messages ?? [])],
|
|
7
12
|
tools: new Set(context?.tools),
|
|
8
13
|
clone() {
|
|
9
14
|
return {
|
package/dist/Context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Context.js","sourceRoot":"","sources":["../Context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"Context.js","sourceRoot":"","sources":["../Context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAyBlD;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,OAAgC;IACtD,OAAO;QACL,OAAO,EAAE,OAAO,EAAE,OAAO;QACzB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,aAAa,EAAE;QACvD,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;QACxC,KAAK,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC;QAC9B,KAAK;YACH,OAAO;gBACL,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE;gBAC3B,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;gBAC5B,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;gBAC1B,KAAK,EAAE,IAAI,CAAC,KAAK;aAClB,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/dist/Definition.d.ts
CHANGED
|
@@ -3,8 +3,22 @@ export type RuneIterator<Y extends Rune<any> = Rune<any>, T = any> = Iterator<Y,
|
|
|
3
3
|
export type RuneIterable<Y extends Rune<any> = Rune<any>, T = any> = Iterable<Y, T> | AsyncIterable<Y, T>;
|
|
4
4
|
export type Definition<Y extends Rune<any> = Rune<any>, T = any> = RuneIterable<Y, T> | (() => RuneIterable<Y, T>);
|
|
5
5
|
export declare namespace Definition {
|
|
6
|
+
/** Extracts the Rune type from a Definition. */
|
|
6
7
|
type Y<X extends Definition> = X extends RuneIterable<infer Y> ? Y : X extends () => RuneIterable<infer Y> ? Y : X extends RuneIterator<infer Y> ? Y : never;
|
|
8
|
+
/** Extracts the result type from a Definition. */
|
|
7
9
|
type T<X extends Definition> = X extends RuneIterable<Rune<any>, infer T> ? T : X extends () => RuneIterable<Rune<any>, infer T> ? T : X extends RuneIterator<Rune<any>, infer T> ? T : never;
|
|
10
|
+
/** Extracts the event type from a Definition. */
|
|
8
11
|
type E<X extends Definition> = Rune.E<Y<X>>;
|
|
12
|
+
/**
|
|
13
|
+
* Converts a Definition into a RuneIterator.
|
|
14
|
+
*
|
|
15
|
+
* This function handles all the different forms a Definition can take:
|
|
16
|
+
* - Synchronous iterables
|
|
17
|
+
* - Asynchronous iterables
|
|
18
|
+
* - Factory functions returning iterables
|
|
19
|
+
*
|
|
20
|
+
* @param definition The definition to unwrap.
|
|
21
|
+
* @returns A RuneIterator ready for consumption.
|
|
22
|
+
*/
|
|
9
23
|
function unwrap<Y extends Rune<any>, T>(definition: Definition<Y, T>): RuneIterator<Y, T>;
|
|
10
24
|
}
|
package/dist/Definition.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
export var Definition;
|
|
2
2
|
(function (Definition) {
|
|
3
|
+
/**
|
|
4
|
+
* Converts a Definition into a RuneIterator.
|
|
5
|
+
*
|
|
6
|
+
* This function handles all the different forms a Definition can take:
|
|
7
|
+
* - Synchronous iterables
|
|
8
|
+
* - Asynchronous iterables
|
|
9
|
+
* - Factory functions returning iterables
|
|
10
|
+
*
|
|
11
|
+
* @param definition The definition to unwrap.
|
|
12
|
+
* @returns A RuneIterator ready for consumption.
|
|
13
|
+
*/
|
|
3
14
|
function unwrap(definition) {
|
|
4
15
|
if (Symbol.iterator in definition) {
|
|
5
16
|
return definition[Symbol.iterator]();
|
package/dist/Definition.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Definition.js","sourceRoot":"","sources":["../Definition.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Definition.js","sourceRoot":"","sources":["../Definition.ts"],"names":[],"mappings":"AAQA,MAAM,KAAW,UAAU,CAuC1B;AAvCD,WAAiB,UAAU;IAgBzB;;;;;;;;;;OAUG;IACH,SAAgB,MAAM,CAAyB,UAA4B;QACzE,IAAI,MAAM,CAAC,QAAQ,IAAI,UAAU,EAAE,CAAC;YAClC,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;QACtC,CAAC;aAAM,IAAI,MAAM,CAAC,aAAa,IAAI,UAAU,EAAE,CAAC;YAC9C,OAAO,UAAU,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;QAC3C,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAA;QAC7B,IAAI,MAAM,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;YAChC,OAAO,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;QACpC,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;IACzC,CAAC;IAXe,iBAAM,SAWrB,CAAA;AACH,CAAC,EAvCgB,UAAU,KAAV,UAAU,QAuC1B"}
|