tardie 0.3.0 → 0.4.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 +44 -35
- package/examples/quickstart/actor.ts +24 -17
- package/package.json +1 -1
- package/src/agent/{budget.ts → components/budget.ts} +16 -1
- package/src/agent/components/code.ts +93 -0
- package/src/agent/{compaction.ts → components/compaction.ts} +17 -2
- package/src/agent/{reply.ts → components/reply.ts} +11 -1
- package/src/agent/components/tool-list.ts +48 -0
- package/src/agent/index.ts +33 -10
- package/src/agent/request.ts +2 -2
- package/src/agent/runtime/agent.ts +136 -0
- package/src/agent/{infer.ts → runtime/infer.ts} +7 -7
- package/src/agent/{tools.ts → runtime/tools.ts} +12 -12
- package/src/agent/spawn.ts +4 -4
- package/src/agent/turn.ts +8 -8
- package/src/client/contract.ts +1 -1
- package/src/code/execute.ts +3 -3
- package/src/code/index.ts +2 -2
- package/src/code/packages.ts +5 -5
- package/src/core/component.ts +102 -0
- package/src/model/model.ts +2 -2
- package/src/server/actor.ts +12 -8
- package/src/agent/capability.ts +0 -281
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Cause, Clock, Context, Effect } from "effect"
|
|
2
2
|
import { EventLog } from "tardie/core/event-log"
|
|
3
3
|
import { transition, type Reactor } from "tardie/core/actor"
|
|
4
|
-
import { modelCalled, textReturned, turnFailed } from "
|
|
4
|
+
import { modelCalled, textReturned, turnFailed } from "../events"
|
|
5
5
|
import type { Event } from "tardie/core/event"
|
|
6
|
-
import type { Action } from "
|
|
6
|
+
import type { Action } from "../events"
|
|
7
7
|
import { trajectoryOf, turnEpochOf, turnView } from "tardie/code/turns"
|
|
8
|
-
import type { ContextPolicy } from "
|
|
8
|
+
import type { ContextPolicy } from "../components/compaction"
|
|
9
9
|
|
|
10
10
|
// The infer reactor: the model loop, and nothing else. A think is owed when the current turn
|
|
11
11
|
// has no unanswered tool call and no terminal; serving marks the attempt, does inference, then
|
|
@@ -28,9 +28,9 @@ export const DEFAULT_INFER_POLICY: InferPolicy = { giveUpAfter: 3, repairAtMost:
|
|
|
28
28
|
export interface InferRequest {
|
|
29
29
|
readonly trajectory: ReadonlyArray<Event>
|
|
30
30
|
readonly system: string
|
|
31
|
-
readonly tools: ReadonlyArray<import("
|
|
31
|
+
readonly tools: ReadonlyArray<import("../request").ToolSpec>
|
|
32
32
|
// What the render truncates and where, stated by the assembly so the binding renders against
|
|
33
|
-
// the same numbers the compaction guard fires on (
|
|
33
|
+
// the same numbers the compaction guard fires on (components/compaction.ts, compactionFor).
|
|
34
34
|
readonly context?: Partial<ContextPolicy>
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -111,11 +111,11 @@ const terminated = (slice: ReadonlyArray<Event>): boolean =>
|
|
|
111
111
|
const terminalKey = (turn: string, epoch: number): string =>
|
|
112
112
|
epoch === 0 ? `tn:${turn}` : `tn:${turn}/${epoch}`
|
|
113
113
|
|
|
114
|
-
// Render derives what the model is shown over this log: the assembly owns it (
|
|
114
|
+
// Render derives what the model is shown over this log: the assembly owns it (runtime/agent.ts,
|
|
115
115
|
// renderOf).
|
|
116
116
|
export type Render = (log: ReadonlyArray<Event>) => {
|
|
117
117
|
readonly system: string
|
|
118
|
-
readonly tools: ReadonlyArray<import("
|
|
118
|
+
readonly tools: ReadonlyArray<import("../request").ToolSpec>
|
|
119
119
|
readonly context?: Partial<ContextPolicy>
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Clock, Effect } from "effect"
|
|
2
2
|
import { transition, type Reactor, type Transition } from "tardie/core/actor"
|
|
3
|
-
import { budgetRequested, toolReturned } from "
|
|
3
|
+
import { budgetRequested, toolReturned } from "../events"
|
|
4
4
|
import type { Event } from "tardie/core/event"
|
|
5
5
|
import { turnView } from "tardie/code/turns"
|
|
6
|
-
import { budgetSpent } from "
|
|
7
|
-
import { answerErrors, outputSchemaOf, repairText } from "
|
|
6
|
+
import { budgetSpent } from "../components/budget"
|
|
7
|
+
import { answerErrors, outputSchemaOf, repairText } from "../contract"
|
|
8
8
|
// The tools reactor: the agent's side of the tool table. The policy here is the same whatever
|
|
9
9
|
// the tools are: the answer contract, the escalation ask, the budget wall, and the unknown-tool
|
|
10
|
-
// error. The work tools themselves come from the mounted
|
|
10
|
+
// error. The work tools themselves come from the mounted components (runtime/agent.ts), so an
|
|
11
11
|
// agent measured against a fixed tool table mounts `toolList` and keeps every behavior here.
|
|
12
12
|
//
|
|
13
13
|
|
|
@@ -24,7 +24,7 @@ export interface PendingCall {
|
|
|
24
24
|
export type Answer = (result: unknown) => Transition<never, never>
|
|
25
25
|
|
|
26
26
|
// Serve returns the transitions one call owes: an empty array while the world still works, and
|
|
27
|
-
// undefined when the call names no tool
|
|
27
|
+
// undefined when the call names no derived tool.
|
|
28
28
|
export type Serve<R = never> = (
|
|
29
29
|
call: PendingCall,
|
|
30
30
|
log: ReadonlyArray<Event>,
|
|
@@ -79,15 +79,15 @@ const decisionFor = (
|
|
|
79
79
|
|
|
80
80
|
// toolsReactorFor derives one transition per pending call, branch by branch. The records each
|
|
81
81
|
// branch appends carry the keys: an answer tr:<callId>, an escalation ask br:<callId>, and
|
|
82
|
-
// whatever key the
|
|
82
|
+
// whatever key the component's own dispatch mints. An escalating call with no parental decision
|
|
83
83
|
// derives nothing (the turn is durably paused); the decision's arrival re-derives the answer.
|
|
84
|
-
// Every branch here is
|
|
84
|
+
// Every branch here is component-independent policy; a tool binding decides only how a
|
|
85
85
|
// work call becomes events.
|
|
86
|
-
// toolsReactorFrom is the policy over a routed serve and a derived tool list: the
|
|
87
|
-
// assembly's entry (
|
|
86
|
+
// toolsReactorFrom is the policy over a routed serve and a derived tool list: the component
|
|
87
|
+
// assembly's entry (runtime/agent.ts), where the tools are information derived from the log.
|
|
88
88
|
export const toolsReactorFrom = <R = never>(
|
|
89
89
|
serve: Serve<R>,
|
|
90
|
-
toolsFor: (log: ReadonlyArray<Event
|
|
90
|
+
toolsFor: (log: ReadonlyArray<Event>, call: PendingCall) => ReadonlyArray<{ readonly name: string }>
|
|
91
91
|
): Reactor<R> => (log) => {
|
|
92
92
|
const call = pendingCall(log)
|
|
93
93
|
if (call === undefined) return []
|
|
@@ -138,7 +138,7 @@ export const toolsReactorFrom = <R = never>(
|
|
|
138
138
|
return [answering({ error: repairText(errors.length > 0 ? errors : ["the answer tool was called with no arguments"]) })]
|
|
139
139
|
}
|
|
140
140
|
// The budget gate: the wall on the turn refuses the work and keeps what the model has. It
|
|
141
|
-
// precedes the serve so a spent turn cannot dispatch, whatever a
|
|
141
|
+
// precedes the serve so a spent turn cannot dispatch, whatever a component would have done.
|
|
142
142
|
if (budgetSpent(log)) {
|
|
143
143
|
return [
|
|
144
144
|
answering({
|
|
@@ -148,7 +148,7 @@ export const toolsReactorFrom = <R = never>(
|
|
|
148
148
|
}
|
|
149
149
|
const served = serve(call, log, answering)
|
|
150
150
|
if (served === undefined) {
|
|
151
|
-
return [answering({ error: `unknown tool: ${call.name}. Call one of: ${toolsFor(log).map((t) => t.name).join(", ")}.` })]
|
|
151
|
+
return [answering({ error: `unknown tool: ${call.name}. Call one of: ${toolsFor(log, call).map((t) => t.name).join(", ")}.` })]
|
|
152
152
|
}
|
|
153
153
|
return served
|
|
154
154
|
}
|
package/src/agent/spawn.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { Router } from "tardie/core/router"
|
|
|
3
3
|
import { Self } from "tardie/core/actor"
|
|
4
4
|
import { Facets } from "tardie/core/facets"
|
|
5
5
|
import type { Package } from "tardie/code/packages"
|
|
6
|
-
import { budgetPolicyOf, type BudgetPolicy } from "./budget"
|
|
6
|
+
import { budgetPolicyOf, type BudgetPolicy } from "./components/budget"
|
|
7
7
|
import { Park } from "tardie/code/errors"
|
|
8
8
|
import { address as addressOf, readAddress } from "tardie/core/router"
|
|
9
9
|
import { replyId } from "tardie/core/message"
|
|
@@ -51,7 +51,7 @@ import { replyId } from "tardie/core/message"
|
|
|
51
51
|
// budget takes the same ceiling the child's own reactor would, and a consumer that moved that
|
|
52
52
|
// ceiling moves both (budget.ts, BudgetPolicy).
|
|
53
53
|
export interface SpawnOptions {
|
|
54
|
-
readonly
|
|
54
|
+
readonly actorNameOf?: () => string | undefined
|
|
55
55
|
readonly reserve?: (callId: string, want: number) => Promise<number>
|
|
56
56
|
readonly shadowOf?: () => boolean
|
|
57
57
|
// The parent's explicit world label, when its own fire named a shared world instead of taking
|
|
@@ -71,7 +71,7 @@ export const agentsPackage = (
|
|
|
71
71
|
options: SpawnOptions & { readonly place?: (callId: string, self: string) => string } = {}
|
|
72
72
|
): Package<Router | Self | Facets> => {
|
|
73
73
|
const place = options.place ?? sibling
|
|
74
|
-
const
|
|
74
|
+
const actorNameOf = options.actorNameOf ?? (() => undefined)
|
|
75
75
|
const reserve = options.reserve ?? (async (_callId: string, want: number) => want)
|
|
76
76
|
const shadowOf = options.shadowOf ?? (() => false)
|
|
77
77
|
const worldOf = options.worldOf ?? (() => undefined)
|
|
@@ -156,7 +156,7 @@ export const agentsPackage = (
|
|
|
156
156
|
if (budget <= 0) return { error: "the run's budget is exhausted; no budget to spawn this agent" }
|
|
157
157
|
// The child works as the same member the parent does: the actor rides every brief in the
|
|
158
158
|
// family, so a run's whole tree resolves connections identically.
|
|
159
|
-
const actor =
|
|
159
|
+
const actor = actorNameOf()
|
|
160
160
|
// The parent's own shadow reading, never the tool args: an agent cannot set or unset it, so
|
|
161
161
|
// a whole run family is shadow by construction from the fire alone. `world` rides along
|
|
162
162
|
// the same way, when the fire named an explicit shared one.
|
package/src/agent/turn.ts
CHANGED
|
@@ -5,28 +5,28 @@ import { send, type Actor } from "tardie/core/actor"
|
|
|
5
5
|
import type { Router } from "tardie/core/router"
|
|
6
6
|
import type { Self } from "tardie/core/actor"
|
|
7
7
|
import type { Facets } from "tardie/core/facets"
|
|
8
|
-
import type { Infer, InferPolicy } from "./infer"
|
|
9
|
-
import type { BudgetPolicy } from "./budget"
|
|
10
|
-
import type { ContextPolicy } from "./compaction"
|
|
8
|
+
import type { Infer, InferPolicy } from "./runtime/infer"
|
|
9
|
+
import type { BudgetPolicy } from "./components/budget"
|
|
10
|
+
import type { ContextPolicy } from "./components/compaction"
|
|
11
11
|
import type { CodePolicy } from "tardie/code/execute"
|
|
12
12
|
import type { WorkspacePolicy } from "tardie/code/workspace"
|
|
13
13
|
|
|
14
|
-
export { Infer } from "./infer"
|
|
14
|
+
export { Infer } from "./runtime/infer"
|
|
15
15
|
|
|
16
16
|
// AgentR is the runtime's needs: Infer for the model, EventLog for settle, Router, Self, and
|
|
17
17
|
// Facets for reply and spawn (the deliver, identity, and observe privileges; core/facets.ts), and
|
|
18
18
|
// KeyValueStore for the spill store code mode writes bounded results to
|
|
19
|
-
// (packages/code/src/spill.ts).
|
|
20
|
-
//
|
|
19
|
+
// (packages/code/src/spill.ts). Components add their own on top (core/component.ts,
|
|
20
|
+
// ComponentRequirements).
|
|
21
21
|
export type AgentR = Infer | EventLog | Router | Self | Facets | KeyValueStore.KeyValueStore
|
|
22
22
|
export type RlmR = AgentR
|
|
23
23
|
|
|
24
24
|
// AgentPolicy is every policy value an assembled agent applies, one field per part that applies
|
|
25
25
|
// one, so a caller sets a single number without listing reactors. Each field is itself partial
|
|
26
26
|
// and fills from its own exported default (infer.ts, budget.ts, compaction.ts,
|
|
27
|
-
// packages/code/src/execute.ts). `infer` is the runtime's policy (
|
|
27
|
+
// packages/code/src/execute.ts). `infer` is the runtime's policy (agentRuntime takes it); `workspace`
|
|
28
28
|
// bounds the workspace package's own read and grep answers (packages/code/src/workspace.ts); the
|
|
29
|
-
// rest ride their
|
|
29
|
+
// rest ride their components (budgetFor, compactionFor, codeModeFor).
|
|
30
30
|
export interface AgentPolicy {
|
|
31
31
|
readonly infer: Partial<InferPolicy>
|
|
32
32
|
readonly budget: Partial<BudgetPolicy>
|
package/src/client/contract.ts
CHANGED
|
@@ -323,7 +323,7 @@ export const projection = <Params extends Schema.Struct.Fields, Result extends S
|
|
|
323
323
|
|
|
324
324
|
// The two names a projection may not claim. The log is not a projection of itself: `events` is the
|
|
325
325
|
// log read back and `stream` is the same log followed, and both are the platform's own guarantee
|
|
326
|
-
// rather than anything an actor derives (projectionsOf refuses either, the way
|
|
326
|
+
// rather than anything an actor derives (projectionsOf refuses either, the way agentRuntime refuses a
|
|
327
327
|
// duplicate tool).
|
|
328
328
|
export const RESERVED_PROJECTIONS: ReadonlyArray<string> = ["events", "stream"]
|
|
329
329
|
|
package/src/code/execute.ts
CHANGED
|
@@ -288,11 +288,11 @@ export interface CodePolicy {
|
|
|
288
288
|
// The packages arrive as values, and what they need arrives with them: the reactor's environment
|
|
289
289
|
// is the spill store plus the union of the packages' own requirements, so a lane assembled with a
|
|
290
290
|
// service-needing package cannot be run where that service is missing (execute.test.ts, "a
|
|
291
|
-
// package's requirements ride its type"). Which packages are passed is the
|
|
291
|
+
// package's requirements ride its type"). Which packages are passed is the component scope: the
|
|
292
292
|
// code can only name these, and the empty array is the powerless lane (packages.ts, Package).
|
|
293
293
|
// Two packages under one name would make `pkg.name` ambiguous in the body's scope, so a duplicate
|
|
294
|
-
// is a construction-time error, the same reading
|
|
295
|
-
// tool name (packages/agent/src/
|
|
294
|
+
// is a construction-time error, the same reading agentRuntime takes of two components claiming one
|
|
295
|
+
// tool name (packages/agent/src/runtime/agent.ts, agentRuntime).
|
|
296
296
|
export const codeReactorFor = <const P extends ReadonlyArray<Package<never>> | ReadonlyArray<Package<unknown>>>(
|
|
297
297
|
policy: Partial<CodePolicy>,
|
|
298
298
|
packages: P
|
package/src/code/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The package root
|
|
2
|
-
//
|
|
1
|
+
// The package root exposes the code reactor and its event keys. Agent assemblies adapt these
|
|
2
|
+
// through codeModeFor in packages/agent/src/components/code.ts.
|
|
3
3
|
export { codeReactor } from "./execute"
|
|
4
4
|
export { codeKeys } from "./events"
|
package/src/code/packages.ts
CHANGED
|
@@ -91,8 +91,8 @@ export const annotationsOf = (pkg: Package<unknown>, method: string): Required<M
|
|
|
91
91
|
...pkg.annotations?.[method]
|
|
92
92
|
})
|
|
93
93
|
|
|
94
|
-
// Package is one named unit of an actor's world face, the dual of
|
|
95
|
-
// face (packages/agent/src/
|
|
94
|
+
// Package is one named unit of an actor's world face, the dual of an AgentComponent on its model
|
|
95
|
+
// face (packages/agent/src/runtime/agent.ts). A component derives what the model is offered
|
|
96
96
|
// (`tools`, `system`) and what settles its calls (`serve`); a package declares what code is
|
|
97
97
|
// offered (`name`, `description`, `docs`) and what settles its calls (`methods`). Code calls
|
|
98
98
|
// methods as `zohorecruit.insert_record(args)`. The platform binds the methods to providers;
|
|
@@ -107,11 +107,11 @@ export const annotationsOf = (pkg: Package<unknown>, method: string): Required<M
|
|
|
107
107
|
// deliberately outside Package: it belongs to the host boundary and gets its own concept once a
|
|
108
108
|
// consumer exists.
|
|
109
109
|
//
|
|
110
|
-
// Which packages an assembly passes is
|
|
110
|
+
// Which packages an assembly passes is component scoping: a task that must never send messages
|
|
111
111
|
// is given no sending package, and the code cannot name what the assembly did not pass. The
|
|
112
112
|
// powerless default is the empty array (execute.ts, codeReactor).
|
|
113
113
|
//
|
|
114
|
-
// `R` is what a package's methods need from the environment, the dual of `
|
|
114
|
+
// `R` is what a package's methods need from the environment, the dual of `AgentComponent<R>` on the
|
|
115
115
|
// model face. A package that reaches for a service names it in its type, and the reactor that
|
|
116
116
|
// runs the package declares the union of what its packages need (execute.ts, codeReactorFor); a
|
|
117
117
|
// package that reaches for nothing is `Package<never>` and runs anywhere.
|
|
@@ -136,7 +136,7 @@ export interface Package<R = never> {
|
|
|
136
136
|
|
|
137
137
|
// PackageRequirements extracts one package's R, so a mixed list infers the union of what its
|
|
138
138
|
// members need rather than collapsing on the first element's R. It is the package-face twin of
|
|
139
|
-
//
|
|
139
|
+
// ComponentRequirements (packages/core/src/component.ts), and what makes the environment a code
|
|
140
140
|
// reactor demands a function of the packages it was passed (execute.test.ts, "a package's
|
|
141
141
|
// requirements ride its type").
|
|
142
142
|
export type PackageRequirements<T> = T extends Package<infer R> ? R : never
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { actor, type Actor, type Reactor, type Transition } from "./actor"
|
|
2
|
+
import type { Event } from "./event"
|
|
3
|
+
import { composeKeys, type KeyFragment } from "./event-log"
|
|
4
|
+
|
|
5
|
+
// Derivation is one component's reading of a log: information for consumers and transitions
|
|
6
|
+
// for the actor runtime. The information follows tla/Projection.tla, ViewFaithful. The
|
|
7
|
+
// transitions follow tla/Reconcile.tla, NoVoid.
|
|
8
|
+
export interface Derivation<I, R = never> {
|
|
9
|
+
readonly info: I
|
|
10
|
+
readonly transitions: ReadonlyArray<Transition<never, R>>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Component derives information and owed work from the same log. Its key fragment declares how
|
|
14
|
+
// the events its transitions append prove commitment to the actor runtime.
|
|
15
|
+
export interface Component<I, R = never> {
|
|
16
|
+
readonly name: string
|
|
17
|
+
readonly keys?: KeyFragment
|
|
18
|
+
readonly derive: (log: ReadonlyArray<Event>) => Derivation<I, R>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// InfoAlgebra states how independently derived information composes. Callers supply the empty
|
|
22
|
+
// value and combination rule because ordering, collisions, and overrides belong to the
|
|
23
|
+
// information's consumer.
|
|
24
|
+
export interface InfoAlgebra<I> {
|
|
25
|
+
readonly empty: I
|
|
26
|
+
readonly combine: (left: I, right: I) => I
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ComponentRuntime interprets composed information as reactors and supplies the key fragments
|
|
30
|
+
// for its protocol. The reactor factory is polymorphic in component requirements because an
|
|
31
|
+
// interpreter may route work whose environment is declared by the component that contributed it.
|
|
32
|
+
export interface ComponentRuntime<I, R = never> {
|
|
33
|
+
readonly name: string
|
|
34
|
+
readonly algebra: InfoAlgebra<I>
|
|
35
|
+
readonly keys: ReadonlyArray<KeyFragment>
|
|
36
|
+
readonly reactors: <C>(infoOf: (log: ReadonlyArray<Event>) => I) => ReadonlyArray<Reactor<R | C>>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ComponentRequirements extracts a component's environment so composition carries the union of every
|
|
40
|
+
// member's requirements to the actor that hosts it.
|
|
41
|
+
export type ComponentRequirements<C> = C extends Component<unknown, infer R> ? R : never
|
|
42
|
+
|
|
43
|
+
// composeComponents derives the algebraic sum of each component's information and concatenates
|
|
44
|
+
// its transitions in component order. The name is explicit because traces and collision errors
|
|
45
|
+
// identify the resulting component with it.
|
|
46
|
+
export const composeComponents = <
|
|
47
|
+
I,
|
|
48
|
+
const Cs extends ReadonlyArray<Component<I, never> | Component<I, unknown>>
|
|
49
|
+
>(
|
|
50
|
+
name: string,
|
|
51
|
+
algebra: InfoAlgebra<I>,
|
|
52
|
+
components: Cs
|
|
53
|
+
): Component<I, ComponentRequirements<Cs[number]>> => {
|
|
54
|
+
const members = components as ReadonlyArray<Component<I, ComponentRequirements<Cs[number]>>>
|
|
55
|
+
const fragments = members.flatMap((component) => component.keys === undefined ? [] : [component.keys])
|
|
56
|
+
const keys = fragments.length === 0
|
|
57
|
+
? undefined
|
|
58
|
+
: {
|
|
59
|
+
prefixes: fragments.flatMap((fragment) => fragment.prefixes),
|
|
60
|
+
keyOf: composeKeys(...fragments)
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
name,
|
|
64
|
+
...(keys === undefined ? {} : { keys }),
|
|
65
|
+
derive: (log) => {
|
|
66
|
+
let info = algebra.empty
|
|
67
|
+
const transitions: Array<Transition<never, ComponentRequirements<Cs[number]>>> = []
|
|
68
|
+
for (const component of members) {
|
|
69
|
+
const derived = component.derive(log)
|
|
70
|
+
info = algebra.combine(info, derived.info)
|
|
71
|
+
transitions.push(...derived.transitions)
|
|
72
|
+
}
|
|
73
|
+
return { info, transitions }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// reactorOf exposes a component's owed-work projection to the existing actor reconciler.
|
|
79
|
+
export const reactorOf = <I, R>(component: Component<I, R>): Reactor<R> =>
|
|
80
|
+
(log) => component.derive(log).transitions
|
|
81
|
+
|
|
82
|
+
// actorOf composes components under one information runtime and adapts their transitions to the
|
|
83
|
+
// existing actor reconciler. Runtime keys compose beside component keys with the same collision
|
|
84
|
+
// rule as composeKeys.
|
|
85
|
+
export const actorOf = <
|
|
86
|
+
I,
|
|
87
|
+
RuntimeR,
|
|
88
|
+
const Cs extends ReadonlyArray<Component<I, never> | Component<I, unknown>>
|
|
89
|
+
>(
|
|
90
|
+
runtime: ComponentRuntime<I, RuntimeR>,
|
|
91
|
+
components: Cs
|
|
92
|
+
): Actor<RuntimeR | ComponentRequirements<Cs[number]>> => {
|
|
93
|
+
type ComponentR = ComponentRequirements<Cs[number]>
|
|
94
|
+
type R = RuntimeR | ComponentR
|
|
95
|
+
const combined = composeComponents(runtime.name, runtime.algebra, components) as Component<I, R>
|
|
96
|
+
const infoOf = (log: ReadonlyArray<Event>): I => combined.derive(log).info
|
|
97
|
+
const reactors = runtime.reactors<ComponentR>(infoOf) as ReadonlyArray<Reactor<R>>
|
|
98
|
+
return actor(
|
|
99
|
+
[...reactors, reactorOf(combined)],
|
|
100
|
+
composeKeys(...runtime.keys, ...(combined.keys === undefined ? [] : [combined.keys]))
|
|
101
|
+
)
|
|
102
|
+
}
|
package/src/model/model.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { openaiCompatibleText } from "@tanstack/ai-openai/compatible"
|
|
|
4
4
|
import * as BedrockRuntime from "@aws-sdk/client-bedrock-runtime"
|
|
5
5
|
import { FetchHttpHandler } from "@smithy/fetch-http-handler"
|
|
6
6
|
import { BedrockConverseTextAdapter, type BEDROCK_CONVERSE_MODELS } from "@tanstack/ai-bedrock"
|
|
7
|
-
import { Infer, type InferRequest } from "tardie
|
|
7
|
+
import { Infer, type InferRequest } from "tardie"
|
|
8
8
|
import type { Action } from "tardie/events"
|
|
9
9
|
import type { Event } from "tardie/core/event"
|
|
10
10
|
import { assertSupportedBun } from "tardie/core/runtime"
|
|
@@ -540,7 +540,7 @@ export const infer = (config: ModelConfig) => {
|
|
|
540
540
|
fetch: fetcher
|
|
541
541
|
})
|
|
542
542
|
// The actor decides the request, render included; the platform maps it to the wire and
|
|
543
|
-
// streams it, holding no opinion about tools (tardie,
|
|
543
|
+
// streams it, holding no opinion about tools (tardie, runtime/agent.ts).
|
|
544
544
|
const req = modelRequest(request.trajectory, request, request.context ?? {})
|
|
545
545
|
const schema = outputSchemaOf(request.trajectory) // the answer parser needs the turn's declared shape
|
|
546
546
|
const stream = adapter.chatStream({
|
package/src/server/actor.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { Schema } from "effect"
|
|
|
2
2
|
import type { Event } from "tardie/core/event"
|
|
3
3
|
import type { Actor } from "tardie/core/actor"
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
actorOf,
|
|
6
|
+
agentRuntime,
|
|
6
7
|
agentsPackage,
|
|
7
8
|
budget,
|
|
8
9
|
codeModeFor,
|
|
@@ -24,7 +25,7 @@ import { inboundOf } from "./projections"
|
|
|
24
25
|
// mounts what is declared here by name (packages/client/src/contract.ts, apiOf).
|
|
25
26
|
|
|
26
27
|
// The assembly, one for every lane: code mode with four packages in scope, plus the three policy
|
|
27
|
-
//
|
|
28
|
+
// components. v1 runs this one assembly and forking is the customization path (apps-server-spec.md,
|
|
28
29
|
// "Explicitly out of scope for v1").
|
|
29
30
|
//
|
|
30
31
|
// What the four packages add up to is what this actor can reach. `agents` fans work out to children
|
|
@@ -33,12 +34,15 @@ import { inboundOf } from "./projections"
|
|
|
33
34
|
// requests to any host. There is no shell: a shell cannot be scoped the way a root or an origin can,
|
|
34
35
|
// and this build has no place to ask an operator whether one command is allowed.
|
|
35
36
|
export const assemblyOf = () =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
actorOf(
|
|
38
|
+
agentRuntime(),
|
|
39
|
+
[
|
|
40
|
+
codeModeFor({ packages: [agentsPackage(), workspacePackage(), filesPackage(), fetchPackage()] }),
|
|
41
|
+
reply,
|
|
42
|
+
budget,
|
|
43
|
+
compaction
|
|
44
|
+
]
|
|
45
|
+
)
|
|
42
46
|
|
|
43
47
|
// ServerR is what this assembly needs bound. It is read off the assembly rather than restated, so a
|
|
44
48
|
// package added above lands in the host's obligation and a host that binds nothing for it fails to
|