liminal 0.5.10 → 0.5.11

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 (84) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/Context.ts +21 -24
  3. package/Fiber.ts +59 -52
  4. package/Handler.ts +2 -2
  5. package/L/L.ts +4 -3
  6. package/L/assistant.ts +6 -6
  7. package/L/catch.ts +15 -2
  8. package/L/emit.ts +3 -7
  9. package/L/{_infer.ts → infer.ts} +9 -6
  10. package/L/{_message.ts → message.ts} +3 -5
  11. package/L/model.ts +1 -3
  12. package/L/rune.ts +8 -26
  13. package/L/strand.ts +99 -0
  14. package/L/stream.ts +3 -5
  15. package/L/system.ts +2 -2
  16. package/L/user.ts +2 -2
  17. package/MessageRegistry.ts +4 -3
  18. package/ModelRegistry.ts +13 -8
  19. package/ToolRegistry.ts +8 -3
  20. package/dist/Context.d.ts +10 -10
  21. package/dist/Context.js +16 -19
  22. package/dist/Context.js.map +1 -1
  23. package/dist/Fiber.d.ts +19 -15
  24. package/dist/Fiber.js +34 -30
  25. package/dist/Fiber.js.map +1 -1
  26. package/dist/Handler.d.ts +2 -2
  27. package/dist/Handler.js +2 -2
  28. package/dist/Handler.js.map +1 -1
  29. package/dist/L/L.d.ts +4 -3
  30. package/dist/L/L.js +4 -3
  31. package/dist/L/L.js.map +1 -1
  32. package/dist/L/assistant.js +6 -6
  33. package/dist/L/assistant.js.map +1 -1
  34. package/dist/L/catch.js +12 -2
  35. package/dist/L/catch.js.map +1 -1
  36. package/dist/L/emit.js +3 -7
  37. package/dist/L/emit.js.map +1 -1
  38. package/dist/L/infer.d.ts +7 -0
  39. package/dist/L/{_infer.js → infer.js} +7 -7
  40. package/dist/L/infer.js.map +1 -0
  41. package/dist/L/message.d.ts +6 -0
  42. package/dist/L/{_message.js → message.js} +3 -5
  43. package/dist/L/message.js.map +1 -0
  44. package/dist/L/model.js +1 -3
  45. package/dist/L/model.js.map +1 -1
  46. package/dist/L/rune.d.ts +1 -6
  47. package/dist/L/rune.js +5 -15
  48. package/dist/L/rune.js.map +1 -1
  49. package/dist/L/strand.d.ts +26 -0
  50. package/dist/L/strand.js +69 -0
  51. package/dist/L/strand.js.map +1 -0
  52. package/dist/L/stream.js +3 -5
  53. package/dist/L/stream.js.map +1 -1
  54. package/dist/L/system.js +2 -2
  55. package/dist/L/system.js.map +1 -1
  56. package/dist/L/user.js +2 -2
  57. package/dist/L/user.js.map +1 -1
  58. package/dist/MessageRegistry.d.ts +2 -2
  59. package/dist/MessageRegistry.js +2 -2
  60. package/dist/MessageRegistry.js.map +1 -1
  61. package/dist/ModelRegistry.d.ts +3 -2
  62. package/dist/ModelRegistry.js +9 -8
  63. package/dist/ModelRegistry.js.map +1 -1
  64. package/dist/ToolRegistry.d.ts +3 -2
  65. package/dist/ToolRegistry.js +5 -2
  66. package/dist/ToolRegistry.js.map +1 -1
  67. package/dist/index.d.ts +0 -1
  68. package/dist/index.js +0 -1
  69. package/dist/index.js.map +1 -1
  70. package/dist/tsconfig.tsbuildinfo +1 -1
  71. package/index.ts +0 -1
  72. package/package.json +4 -4
  73. package/Agent.ts +0 -38
  74. package/L/branch.ts +0 -33
  75. package/dist/Agent.d.ts +0 -18
  76. package/dist/Agent.js +0 -20
  77. package/dist/Agent.js.map +0 -1
  78. package/dist/L/_infer.d.ts +0 -4
  79. package/dist/L/_infer.js.map +0 -1
  80. package/dist/L/_message.d.ts +0 -6
  81. package/dist/L/_message.js.map +0 -1
  82. package/dist/L/branch.d.ts +0 -11
  83. package/dist/L/branch.js +0 -24
  84. package/dist/L/branch.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # liminal
2
2
 
3
+ ## 0.5.11
4
+
5
+ ### Patch Changes
6
+
7
+ - cf42ed2: Agent -> Strand. Making the API more uniform. Ie. Agent -> L.strand. L.branch -> L.strand.
8
+ - Updated dependencies [cf42ed2]
9
+ - liminal-schema@0.0.5
10
+ - liminal-util@0.0.6
11
+
3
12
  ## 0.5.10
4
13
 
5
14
  ### Patch Changes
package/Context.ts CHANGED
@@ -1,43 +1,40 @@
1
- import { assert } from "liminal-util"
2
1
  import { AsyncLocalStorage } from "node:async_hooks"
3
2
 
4
3
  const storage = new AsyncLocalStorage<Context>()
5
4
 
6
- export class Context extends Map<ContextHandle, unknown> {
7
- static ensure(): Context {
8
- const context = storage.getStore()
9
- assert(context)
10
- return context
11
- }
12
-
13
- get<V>(context: ContextHandle<V>): V | undefined {
14
- return super.get(context) as never
5
+ export class Context extends Map<ContextPart, unknown> {
6
+ static get(): Context | undefined {
7
+ return storage.getStore()
15
8
  }
16
9
 
17
- set<V>(context: ContextHandle<V>, value: V): this {
18
- super.set(context, value)
19
- return this
10
+ run<R>(f: () => R): R {
11
+ return storage.run(this, f)
20
12
  }
21
13
 
22
- run<R>(callback: () => R): R {
23
- return storage.run(this, callback)
24
- }
25
-
26
- clone(overrides?: Iterable<[ContextHandle, unknown]>): Context {
27
- const context = new Context(overrides)
14
+ fork(): Context {
15
+ const context = new Context()
28
16
  for (const [handle, value] of this.entries()) {
29
17
  if (!context.has(handle)) {
30
- context.set(handle, handle.clone?.(value) ?? value)
18
+ context.set(handle, handle.fork(value))
31
19
  }
32
20
  }
33
21
  return context
34
22
  }
35
23
  }
36
24
 
37
- export type ContextHandle<V = any> = {
38
- clone: ((value: V) => V) | undefined
25
+ export interface ContextPart<V = any> {
26
+ fork(parent?: V): V
27
+ get(): V | undefined
28
+ debug?: string
39
29
  }
40
30
 
41
- export function ContextHandle<V>(clone?: (value: V) => V): ContextHandle<V> {
42
- return { clone }
31
+ export function ContextPart<V>(fork: (parent?: V) => V, debug?: string): ContextPart<V> {
32
+ const self: ContextPart<V> = {
33
+ fork,
34
+ get() {
35
+ return Context.get()?.get(self) as never
36
+ },
37
+ ...debug && { debug },
38
+ }
39
+ return self
43
40
  }
package/Fiber.ts CHANGED
@@ -1,73 +1,63 @@
1
1
  import { attachCustomInspect } from "liminal-util"
2
2
  import { Context } from "./Context.ts"
3
3
  import { type Handler, HandlerContext } from "./Handler.ts"
4
+ import { ToolRegistry, ToolRegistryContext } from "./index.ts"
4
5
  import { FiberCreated, FiberRejected, FiberResolved, FiberStarted } from "./LEvent.ts"
5
- import type { Rune } from "./Rune.ts"
6
+ import { MessageRegistry, MessageRegistryContext } from "./MessageRegistry.ts"
7
+ import { ModelRegistry, ModelRegistryContext } from "./ModelRegistry.ts"
8
+ import { type Rune, RuneKey } from "./Rune.ts"
6
9
  import { Runic } from "./Runic.ts"
7
- export type FiberStatus<T> = {
8
- type: "untouched"
9
- } | {
10
- type: "pending"
11
- self: AbortSignal
12
- promise: Promise<T>
13
- } | {
14
- type: "aborted"
15
- reason: unknown
16
- } | {
17
- type: "resolved"
18
- value: T
19
- } | {
20
- type: "rejected"
21
- exception: unknown
10
+
11
+ export interface FiberConfig {
12
+ parent?: Fiber
13
+ signal?: AbortSignal
14
+ context: Context
22
15
  }
23
16
 
24
17
  export class Fiber<T = any> {
25
- static nextIndex: number = 0
18
+ static *[Symbol.iterator](): Generator<Rune<never>, Fiber> {
19
+ return yield Object.assign((fiber: Fiber) => fiber, {
20
+ [RuneKey]: true,
21
+ debug: "current_fiber",
22
+ } as never)
23
+ }
26
24
 
27
- declare T: T
25
+ static nextIndex: number = 0
28
26
  readonly index: number = Fiber.nextIndex++
29
27
 
30
- #runic: Runic<Rune, T>
31
- declare readonly parent?: Fiber
32
- #context: Context = Context.ensure()
33
- #handler?: Handler = this.#context.get(HandlerContext)
28
+ readonly #context: Context
29
+ readonly #runic: Runic<Rune, T>
30
+ readonly #handler: Handler | undefined = HandlerContext.get()
31
+ readonly #configSignal?: AbortSignal
34
32
 
35
- signal: AbortSignal
36
- either: AbortSignal
37
- abort: (reason?: any) => void
33
+ declare readonly parent?: Fiber
38
34
 
39
35
  status: FiberStatus<T> = { type: "untouched" }
36
+ controller: AbortController = new AbortController()
40
37
 
41
- constructor(runic: Runic<Rune, T>, parent?: Fiber) {
38
+ constructor(runic: Runic<Rune, T>, config: FiberConfig) {
42
39
  this.#runic = runic
43
- if (parent) {
44
- this.parent = parent
45
- }
46
- const controller = new AbortController()
47
- this.signal = controller.signal
48
- this.either = AbortSignal.any([
49
- ...this.parent?.signal ? [this.parent.signal] : [],
50
- this.signal,
51
- ])
52
- this.abort = controller.abort.bind(controller)
53
- this.#handler?.call(this, new FiberCreated())
40
+ const { context, parent, signal } = config
41
+ this.#context = context
42
+ if (parent) this.parent = parent
43
+ if (signal) this.#configSignal = signal
44
+ this.handle(new FiberCreated())
54
45
  }
55
46
 
56
- fork<T>(runic: Runic<Rune, T>): Fiber<T> {
57
- return new Fiber(runic, this)
47
+ handle(event: any) {
48
+ this.#handler?.call(this, event)
58
49
  }
59
50
 
60
- resolution(this: Fiber<T>): Promise<T> {
61
- const { status, abort } = this
62
- switch (status.type) {
51
+ resolution(): Promise<T> {
52
+ switch (this.status.type) {
63
53
  case "untouched": {
64
54
  const { promise, resolve, reject } = Promise.withResolvers<T>()
65
55
  this.status = {
66
56
  type: "pending",
67
- self: this.signal,
57
+ self: this.controller.signal,
68
58
  promise,
69
59
  }
70
- this.#handler?.call(this, new FiberStarted())
60
+ this.handle(new FiberStarted())
71
61
  const iterator = Runic.unwrap(this.#runic)
72
62
  let nextArg: unknown
73
63
  this.#context.run(async () => {
@@ -83,32 +73,32 @@ export class Fiber<T = any> {
83
73
  type: "resolved",
84
74
  value,
85
75
  }
86
- this.#handler?.call(this, new FiberResolved(value))
87
- abort()
76
+ this.handle(new FiberResolved(value))
77
+ this.controller.abort()
88
78
  resolve(value)
89
79
  } catch (exception) {
90
80
  this.status = {
91
81
  type: "rejected",
92
82
  exception,
93
83
  }
94
- this.#handler?.call(this, new FiberRejected(exception))
95
- abort(exception)
84
+ this.handle(new FiberRejected(exception))
85
+ this.controller.abort()
96
86
  reject(exception)
97
87
  }
98
88
  })
99
89
  return promise
100
90
  }
101
91
  case "pending": {
102
- return status.promise
92
+ return this.status.promise
103
93
  }
104
94
  case "resolved": {
105
- return Promise.resolve(status.value)
95
+ return Promise.resolve(this.status.value)
106
96
  }
107
97
  case "rejected": {
108
- return Promise.reject(status.exception)
98
+ return Promise.reject(this.status.exception)
109
99
  }
110
100
  case "aborted": {
111
- return Promise.reject(status.reason)
101
+ return Promise.reject(this.status.reason)
112
102
  }
113
103
  }
114
104
  }
@@ -117,3 +107,20 @@ export class Fiber<T = any> {
117
107
  attachCustomInspect(this, ({ index, parent }) => ({ index, ...parent && { parent } }))
118
108
  }
119
109
  }
110
+
111
+ export type FiberStatus<T> = {
112
+ type: "untouched"
113
+ } | {
114
+ type: "pending"
115
+ self: AbortSignal
116
+ promise: Promise<T>
117
+ } | {
118
+ type: "aborted"
119
+ reason: unknown
120
+ } | {
121
+ type: "resolved"
122
+ value: T
123
+ } | {
124
+ type: "rejected"
125
+ exception: unknown
126
+ }
package/Handler.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { ContextHandle } from "./Context.ts"
1
+ import { ContextPart as ContextPart } from "./Context.ts"
2
2
  import type { Fiber } from "./Fiber.ts"
3
3
 
4
4
  export type Handler<E = any> = [(this: Fiber, event: E) => void][0]
5
5
 
6
- export const HandlerContext: ContextHandle<Handler | undefined> = ContextHandle()
6
+ export const HandlerContext: ContextPart<Handler | undefined> = ContextPart((parent) => parent, "handler")
package/L/L.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  export * from "liminal-schema/factories"
2
- export * from "./_infer.ts"
3
- export * from "./_message.ts"
4
2
  export * from "./assistant.ts"
5
- export * from "./branch.ts"
6
3
  export * from "./catch.ts"
7
4
  export * from "./emit.ts"
5
+ export * from "./infer.ts"
6
+ export * from "./message.ts"
8
7
  export * from "./model.ts"
8
+ export * from "./rune.ts"
9
+ export * from "./strand.ts"
9
10
  export * from "./stream.ts"
10
11
  export * from "./system.ts"
11
12
  export * from "./user.ts"
package/L/assistant.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { type LType, toJSONSchema, validate } from "liminal-schema"
2
2
  import type { LEvent } from "../LEvent.ts"
3
3
  import type { Rune } from "../Rune.ts"
4
- import { _infer } from "./_infer.ts"
5
- import { _message } from "./_message.ts"
4
+ import { infer } from "./infer.ts"
5
+ import { message } from "./message.ts"
6
6
  import { rune } from "./rune.ts"
7
7
 
8
8
  export interface assistant extends Iterable<Rune<LEvent>, string> {
@@ -12,15 +12,15 @@ export interface assistant extends Iterable<Rune<LEvent>, string> {
12
12
  export const assistant: assistant = Object.assign(
13
13
  function*<T>(type: LType<T>): Generator<Rune<LEvent>, T> {
14
14
  const schema = toJSONSchema(type)
15
- const inference = yield* _infer(schema)
16
- yield* _message("assistant", [{ part: inference }])
15
+ const inference = yield* infer(schema)
16
+ yield* message("assistant", [{ part: inference }])
17
17
  const input = JSON.parse(inference)
18
18
  return yield* rune(() => validate(type, input), "validate_assistant_message")
19
19
  },
20
20
  {
21
21
  *[Symbol.iterator]() {
22
- const inference = yield* _infer()
23
- yield* _message("assistant", [{ part: inference }])
22
+ const inference = yield* infer()
23
+ yield* message("assistant", [{ part: inference }])
24
24
  return inference
25
25
  },
26
26
  },
package/L/catch.ts CHANGED
@@ -1,12 +1,25 @@
1
+ import { assert } from "liminal-util"
2
+ import { Context } from "../Context.ts"
3
+ import { Fiber } from "../Fiber.ts"
1
4
  import type { Rune } from "../Rune.ts"
2
5
  import type { Runic } from "../Runic.ts"
3
6
  import { rune } from "./rune.ts"
4
7
 
5
8
  export { catch_ as catch }
9
+
6
10
  function* catch_<Y extends Rune, T>(runic: Runic<Y, T>): Generator<Rune<Y>, CatchResult<T>> {
7
- return yield* rune(async (fiber) => {
11
+ return yield* rune(async (parent) => {
8
12
  try {
9
- return { resolved: await fiber.fork(runic).resolution() }
13
+ const context = Context.get()
14
+ assert(context)
15
+ return {
16
+ resolved: await context.fork().run(() =>
17
+ new Fiber(runic, {
18
+ context: context.fork(),
19
+ parent,
20
+ }).resolution()
21
+ ),
22
+ }
10
23
  } catch (exception: unknown) {
11
24
  return { rejected: exception }
12
25
  }
package/L/emit.ts CHANGED
@@ -1,14 +1,10 @@
1
1
  import type { EnsureNarrow } from "liminal-util"
2
- import { Context } from "../Context.ts"
3
- import { HandlerContext } from "../Handler.ts"
2
+ import { Fiber } from "../Fiber.ts"
4
3
  import type { Rune } from "../Rune.ts"
5
- import { rune } from "./rune.ts"
6
4
 
7
5
  export interface emit<E> extends Generator<Rune<E>, void> {}
8
6
 
9
7
  export function* emit<const E>(event: EnsureNarrow<E>): emit<E> {
10
- const context = Context.ensure()
11
- const handler = context.get(HandlerContext)
12
- const fiber = yield* rune
13
- handler?.call(fiber, event)
8
+ const self = yield* Fiber
9
+ self.handle(event)
14
10
  }
@@ -1,6 +1,5 @@
1
1
  import type { SchemaObject } from "liminal-schema"
2
2
  import { assert } from "liminal-util"
3
- import { Context } from "../Context.ts"
4
3
  import { InferenceRequested, Inferred, type LEvent } from "../LEvent.ts"
5
4
  import { MessageRegistryContext } from "../MessageRegistry.ts"
6
5
  import { ModelRegistryContext } from "../ModelRegistry.ts"
@@ -9,24 +8,28 @@ import { RequestCounter } from "./_common.ts"
9
8
  import { emit } from "./emit.ts"
10
9
  import { rune } from "./rune.ts"
11
10
 
12
- export function* _infer(schema?: SchemaObject): Generator<Rune<LEvent>, string> {
13
- const context = Context.ensure()
14
- const modelRegistry = context.get(ModelRegistryContext)
11
+ export { infer_ as infer }
12
+
13
+ interface infer_ extends Generator<Rune<LEvent>, string> {}
14
+
15
+ function* infer_(schema?: SchemaObject): infer_ {
16
+ const modelRegistry = ModelRegistryContext.get()
15
17
  assert(modelRegistry)
16
18
  const model = modelRegistry.peek()
17
19
  assert(model)
18
20
  const requestId = RequestCounter.next()
19
21
  yield* emit(new InferenceRequested(requestId, schema))
20
- const messageRegistry = context.get(MessageRegistryContext)
22
+ const messageRegistry = MessageRegistryContext.get()
21
23
  assert(messageRegistry)
22
24
  const inference = yield* rune((fiber) =>
23
25
  model
24
26
  .seal({
25
27
  messages: messageRegistry.messages,
26
28
  schema,
27
- signal: fiber.signal,
29
+ signal: fiber.controller.signal,
28
30
  })
29
31
  .resolve(), "infer")
30
32
  yield* emit(new Inferred(requestId, inference))
31
33
  return inference
32
34
  }
35
+ Object.defineProperty(infer_, "name", { value: "infer" })
@@ -1,16 +1,14 @@
1
1
  import { assert } from "liminal-util"
2
- import { Context } from "../Context.ts"
3
2
  import { type LEvent, MessageAppended } from "../LEvent.ts"
4
3
  import type { ContentPart, Message, MessageRole } from "../Message.ts"
5
4
  import { MessageRegistryContext } from "../MessageRegistry.ts"
6
5
  import type { Rune } from "../Rune.ts"
7
6
  import { emit } from "./emit.ts"
8
7
 
9
- export interface _message extends Generator<Rune<LEvent>, void> {}
8
+ export interface message extends Generator<Rune<LEvent>, void> {}
10
9
 
11
- export function* _message(role: MessageRole, content: Array<ContentPart>): _message {
12
- const context = Context.ensure()
13
- const messageRegistry = context.get(MessageRegistryContext)
10
+ export function* message(role: MessageRole, content: Array<ContentPart>): message {
11
+ const messageRegistry = MessageRegistryContext.get()
14
12
  assert(messageRegistry)
15
13
  const message: Message = { role, content }
16
14
  yield* emit(new MessageAppended(message))
package/L/model.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { assert } from "liminal-util"
2
- import { Context } from "../Context.ts"
3
2
  import { ModelRegistered } from "../LEvent.ts"
4
3
  import type { Model } from "../Model.ts"
5
4
  import { ModelRegistryContext } from "../ModelRegistry.ts"
@@ -9,8 +8,7 @@ import { emit } from "./emit.ts"
9
8
  export interface model extends Generator<Rune<ModelRegistered>, void> {}
10
9
 
11
10
  export function* model(model: Model): model {
12
- const context = Context.ensure()
13
- const registry = context.get(ModelRegistryContext)
11
+ const registry = ModelRegistryContext.get()
14
12
  assert(registry)
15
13
  registry.register(model)
16
14
  yield* emit(new ModelRegistered(model))
package/L/rune.ts CHANGED
@@ -1,30 +1,12 @@
1
1
  import { Fiber } from "../Fiber.ts"
2
2
  import { type Rune, RuneKey } from "../Rune.ts"
3
3
 
4
- export interface rune extends Iterable<Rune<never>, Fiber> {
5
- <R>(source: (fiber: Fiber) => R, debug?: string): Iterable<Rune<never>, Awaited<R>> & {
6
- <E>(): Generator<Rune<E>, Awaited<R>>
7
- }
4
+ export function* rune<R>(
5
+ source: (fiber: Fiber) => R,
6
+ debug?: string,
7
+ ): Generator<Rune<never>, Awaited<R>> {
8
+ return yield Object.assign(source, {
9
+ [RuneKey]: true,
10
+ debug,
11
+ }) as never
8
12
  }
9
- export const rune: rune = Object.assign(
10
- function<R>(source: (fiber: Fiber) => R, debug?: string) {
11
- return Object.assign(
12
- function*<E>(): Generator<Rune<E>, Awaited<R>> {
13
- return yield Object.assign(source, { [RuneKey]: true, debug } as never)
14
- },
15
- {
16
- *[Symbol.iterator](): Generator<Rune<never>, Awaited<R>> {
17
- return yield Object.assign(source, { [RuneKey]: true, debug } as never)
18
- },
19
- },
20
- )
21
- },
22
- {
23
- *[Symbol.iterator](): Generator<Rune<never>, Fiber> {
24
- return yield Object.assign((fiber: Fiber) => fiber, {
25
- [RuneKey]: true,
26
- debug: "get_current_fiber",
27
- } as never)
28
- },
29
- },
30
- )
package/L/strand.ts ADDED
@@ -0,0 +1,99 @@
1
+ import { Context } from "../Context.ts"
2
+ import { Fiber } from "../Fiber.ts"
3
+ import { HandlerContext } from "../Handler.ts"
4
+ import { MessageRegistry, MessageRegistryContext } from "../MessageRegistry.ts"
5
+ import { ModelRegistry, ModelRegistryContext } from "../ModelRegistry.ts"
6
+ import { type Rune } from "../Rune.ts"
7
+ import type { Runic } from "../Runic.ts"
8
+ import { ToolRegistry, ToolRegistryContext } from "../ToolRegistry.ts"
9
+ import { rune } from "./rune.ts"
10
+
11
+ export interface StrandConfig<T = any, E = any> {
12
+ handler?: ((this: Fiber<T>, event: E) => void) | undefined
13
+ models?: ModelRegistry | undefined
14
+ messages?: MessageRegistry | undefined
15
+ tools?: ToolRegistry | undefined
16
+ signal?: AbortSignal | undefined
17
+ }
18
+
19
+ export interface strand<Y extends Rune, T> extends Iterable<Y, T>, PromiseLike<T> {}
20
+
21
+ export function strand<X extends Runic>(
22
+ runic: X,
23
+ config?: StrandConfig<Runic.T<X>, Rune.E<Runic.Y<X>>>,
24
+ ): strand<Runic.Y<X>, Runic.T<X>>
25
+ export function strand<XA extends Array<Runic>>(
26
+ runics: XA,
27
+ config?: StrandConfig<{ [I in keyof XA]: Runic.T<XA[I]> }, Rune.E<Runic.Y<XA[number]>>>,
28
+ ): strand<Runic.Y<XA[number]> | Rune<never>, { [I in keyof XA]: Runic.T<XA[I]> }>
29
+ export function strand<XR extends Record<keyof any, Runic>>(
30
+ runics: XR,
31
+ config?: StrandConfig<{ [K in keyof XR]: Runic.T<XR[K]> }, Rune.E<Runic.Y<XR[keyof XR]>>>,
32
+ ): strand<Runic.Y<XR[keyof XR]> | Rune<never>, { [K in keyof XR]: Runic.T<XR[K]> }>
33
+ export function strand(
34
+ value: Runic | Array<Runic> | Record<keyof any, Runic>,
35
+ config?: StrandConfig,
36
+ ): strand<Rune, any> {
37
+ return {
38
+ *[Symbol.iterator](): Generator<Rune, any> {
39
+ const parent = yield* Fiber
40
+ if (Array.isArray(value)) {
41
+ const fibers = value.map((runic) =>
42
+ new Fiber(runic, {
43
+ parent,
44
+ context: makeContext(),
45
+ })
46
+ )
47
+ return yield* rune(() => Promise.all(fibers.map((fiber) => fiber.resolution())), "strand")
48
+ } else if (typeof value === "object") {
49
+ const fibers = Object.values(value).map((runic) =>
50
+ new Fiber(runic, {
51
+ parent,
52
+ context: makeContext(),
53
+ })
54
+ )
55
+ return yield* rune(async () => {
56
+ const keys = Object.keys(value)
57
+ return await Promise
58
+ .all(fibers.map((fiber) => fiber.resolution()))
59
+ .then((resolved) => resolved.map((value, i) => [keys[i], value]))
60
+ .then(Object.fromEntries)
61
+ }, "strand")
62
+ }
63
+ const self = new Fiber(typeof value === "function" ? value() : value, {
64
+ parent,
65
+ context: makeContext(),
66
+ })
67
+ return yield* rune(() => self.resolution(), "strand")
68
+ },
69
+ then(onfulfilled, onrejected) {
70
+ return new Fiber(this, { context: makeContext() }).resolution().then(onfulfilled, onrejected)
71
+ },
72
+ }
73
+
74
+ function makeContext() {
75
+ let context = Context.get()?.fork()
76
+ if (!context) {
77
+ context = new Context([
78
+ [ModelRegistryContext, new ModelRegistry()],
79
+ [MessageRegistryContext, new MessageRegistry()],
80
+ [ToolRegistryContext, new ToolRegistry()],
81
+ ])
82
+ }
83
+ if (config) {
84
+ if ("handler" in config) {
85
+ context.set(HandlerContext, config.handler)
86
+ }
87
+ if ("models" in config) {
88
+ context.set(ModelRegistryContext, config.models?.clone() ?? new ModelRegistry())
89
+ }
90
+ if ("messages" in config) {
91
+ context.set(MessageRegistryContext, config.messages?.clone() ?? new MessageRegistry())
92
+ }
93
+ if ("tools" in config) {
94
+ context.set(ToolRegistryContext, config.tools?.clone() ?? new ToolRegistry())
95
+ }
96
+ }
97
+ return context
98
+ }
99
+ }
package/L/stream.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { assert } from "liminal-util"
2
- import { Context } from "../Context.ts"
3
2
  import { InferenceRequested, type LEvent } from "../LEvent.ts"
4
3
  import { MessageRegistryContext } from "../MessageRegistry.ts"
5
4
  import { ModelRegistryContext } from "../ModelRegistry.ts"
@@ -12,20 +11,19 @@ export interface stream extends Iterable<Rune<LEvent>, ReadableStream<string>> {
12
11
 
13
12
  export const stream: stream = {
14
13
  *[Symbol.iterator](): Generator<Rune<LEvent>, ReadableStream<string>> {
15
- const context = Context.ensure()
16
- const modelRegistry = context.get(ModelRegistryContext)
14
+ const modelRegistry = ModelRegistryContext.get()
17
15
  assert(modelRegistry)
18
16
  const model = modelRegistry.peek()
19
17
  assert(model)
20
18
  const requestId = RequestCounter.next()
21
19
  yield* emit(new InferenceRequested(requestId))
22
- const messageRegistry = context.get(MessageRegistryContext)
20
+ const messageRegistry = MessageRegistryContext.get()
23
21
  assert(messageRegistry)
24
22
  return yield* rune((fiber) =>
25
23
  model
26
24
  .seal({
27
25
  messages: messageRegistry.messages,
28
- signal: fiber.signal,
26
+ signal: fiber.controller.signal,
29
27
  })
30
28
  .stream(), "stream")
31
29
  },
package/L/system.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isTemplateStringsArray } from "liminal-util"
2
2
  import type { LEvent } from "../LEvent.ts"
3
3
  import type { Rune } from "../Rune.ts"
4
- import { _message } from "./_message.ts"
4
+ import { message } from "./message.ts"
5
5
 
6
6
  export interface system extends Generator<Rune<LEvent>, void> {}
7
7
 
@@ -9,5 +9,5 @@ export function system(template: TemplateStringsArray, ...substitutions: Array<s
9
9
  export function system(value: string): system
10
10
  export function system(e0: TemplateStringsArray | string, ...rest: Array<string>): system {
11
11
  const part = isTemplateStringsArray(e0) ? String.raw(e0, ...rest) : e0
12
- return _message("system", [{ part }])
12
+ return message("system", [{ part }])
13
13
  }
package/L/user.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { isTemplateStringsArray } from "liminal-util"
2
2
  import type { LEvent } from "../LEvent.ts"
3
3
  import type { Rune } from "../Rune.ts"
4
- import { _message } from "./_message.ts"
4
+ import { message } from "./message.ts"
5
5
 
6
6
  export interface user extends Generator<Rune<LEvent>, void> {}
7
7
 
@@ -9,5 +9,5 @@ export function user(template: TemplateStringsArray, ...substitutions: Array<str
9
9
  export function user(value: string): user
10
10
  export function user(e0: TemplateStringsArray | string, ...rest: Array<string>): user {
11
11
  const part = isTemplateStringsArray(e0) ? String.raw(e0, ...rest) : e0
12
- return _message("user", [{ part }])
12
+ return message("user", [{ part }])
13
13
  }
@@ -1,4 +1,4 @@
1
- import { ContextHandle } from "./Context.ts"
1
+ import { ContextPart } from "./Context.ts"
2
2
  import type { Message } from "./Message.ts"
3
3
 
4
4
  export class MessageRegistry {
@@ -16,6 +16,7 @@ export class MessageRegistry {
16
16
  }
17
17
  }
18
18
 
19
- export const MessageRegistryContext: ContextHandle<MessageRegistry> = ContextHandle(({ messages }) =>
20
- new MessageRegistry([...messages])
19
+ export const MessageRegistryContext: ContextPart<MessageRegistry> = ContextPart(
20
+ (parent) => parent?.clone() ?? new MessageRegistry(),
21
+ "message_registry",
21
22
  )