@aid-framework/runtime 0.0.0 → 0.1.39

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 (188) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +53 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/agents/deep_agents.d.ts +78 -0
  5. package/dist/agents/deep_agents.d.ts.map +1 -0
  6. package/dist/agents/deep_agents.js +477 -0
  7. package/dist/agents/deep_agents.js.map +1 -0
  8. package/dist/agents/engine.d.ts +85 -0
  9. package/dist/agents/engine.d.ts.map +1 -0
  10. package/dist/agents/engine.js +129 -0
  11. package/dist/agents/engine.js.map +1 -0
  12. package/dist/agents/gateway_chat_model.d.ts +151 -0
  13. package/dist/agents/gateway_chat_model.d.ts.map +1 -0
  14. package/dist/agents/gateway_chat_model.js +350 -0
  15. package/dist/agents/gateway_chat_model.js.map +1 -0
  16. package/dist/agents/guardrail_middleware.d.ts +57 -0
  17. package/dist/agents/guardrail_middleware.d.ts.map +1 -0
  18. package/dist/agents/guardrail_middleware.js +85 -0
  19. package/dist/agents/guardrail_middleware.js.map +1 -0
  20. package/dist/agents/guardrails.d.ts +124 -0
  21. package/dist/agents/guardrails.d.ts.map +1 -0
  22. package/dist/agents/guardrails.js +336 -0
  23. package/dist/agents/guardrails.js.map +1 -0
  24. package/dist/agents/index.d.ts +15 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +15 -0
  27. package/dist/agents/index.js.map +1 -0
  28. package/dist/agents/ir.d.ts +144 -0
  29. package/dist/agents/ir.d.ts.map +1 -0
  30. package/dist/agents/ir.js +513 -0
  31. package/dist/agents/ir.js.map +1 -0
  32. package/dist/agents/loop.d.ts +145 -0
  33. package/dist/agents/loop.d.ts.map +1 -0
  34. package/dist/agents/loop.js +1025 -0
  35. package/dist/agents/loop.js.map +1 -0
  36. package/dist/agents/memory.d.ts +115 -0
  37. package/dist/agents/memory.d.ts.map +1 -0
  38. package/dist/agents/memory.js +258 -0
  39. package/dist/agents/memory.js.map +1 -0
  40. package/dist/agents/state.d.ts +137 -0
  41. package/dist/agents/state.d.ts.map +1 -0
  42. package/dist/agents/state.js +255 -0
  43. package/dist/agents/state.js.map +1 -0
  44. package/dist/concurrency.d.ts +36 -0
  45. package/dist/concurrency.d.ts.map +1 -0
  46. package/dist/concurrency.js +86 -0
  47. package/dist/concurrency.js.map +1 -0
  48. package/dist/control.d.ts +116 -0
  49. package/dist/control.d.ts.map +1 -0
  50. package/dist/control.js +281 -0
  51. package/dist/control.js.map +1 -0
  52. package/dist/cost.d.ts +95 -0
  53. package/dist/cost.d.ts.map +1 -0
  54. package/dist/cost.js +161 -0
  55. package/dist/cost.js.map +1 -0
  56. package/dist/errors.d.ts +213 -0
  57. package/dist/errors.d.ts.map +1 -0
  58. package/dist/errors.js +316 -0
  59. package/dist/errors.js.map +1 -0
  60. package/dist/evals/dataset.d.ts +45 -0
  61. package/dist/evals/dataset.d.ts.map +1 -0
  62. package/dist/evals/dataset.js +147 -0
  63. package/dist/evals/dataset.js.map +1 -0
  64. package/dist/evals/gate.d.ts +236 -0
  65. package/dist/evals/gate.d.ts.map +1 -0
  66. package/dist/evals/gate.js +572 -0
  67. package/dist/evals/gate.js.map +1 -0
  68. package/dist/evals/metrics.d.ts +141 -0
  69. package/dist/evals/metrics.d.ts.map +1 -0
  70. package/dist/evals/metrics.js +364 -0
  71. package/dist/evals/metrics.js.map +1 -0
  72. package/dist/evals/predicate.d.ts +79 -0
  73. package/dist/evals/predicate.d.ts.map +1 -0
  74. package/dist/evals/predicate.js +178 -0
  75. package/dist/evals/predicate.js.map +1 -0
  76. package/dist/evals/runner.d.ts +94 -0
  77. package/dist/evals/runner.d.ts.map +1 -0
  78. package/dist/evals/runner.js +202 -0
  79. package/dist/evals/runner.js.map +1 -0
  80. package/dist/gateway.d.ts +118 -0
  81. package/dist/gateway.d.ts.map +1 -0
  82. package/dist/gateway.js +250 -0
  83. package/dist/gateway.js.map +1 -0
  84. package/dist/index.d.ts +83 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +59 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/internal/json.d.ts +44 -0
  89. package/dist/internal/json.d.ts.map +1 -0
  90. package/dist/internal/json.js +90 -0
  91. package/dist/internal/json.js.map +1 -0
  92. package/dist/internal/text.d.ts +17 -0
  93. package/dist/internal/text.d.ts.map +1 -0
  94. package/dist/internal/text.js +22 -0
  95. package/dist/internal/text.js.map +1 -0
  96. package/dist/pipeline.d.ts +80 -0
  97. package/dist/pipeline.d.ts.map +1 -0
  98. package/dist/pipeline.js +159 -0
  99. package/dist/pipeline.js.map +1 -0
  100. package/dist/policy.d.ts +52 -0
  101. package/dist/policy.d.ts.map +1 -0
  102. package/dist/policy.js +199 -0
  103. package/dist/policy.js.map +1 -0
  104. package/dist/prompts.d.ts +86 -0
  105. package/dist/prompts.d.ts.map +1 -0
  106. package/dist/prompts.js +337 -0
  107. package/dist/prompts.js.map +1 -0
  108. package/dist/providers/base.d.ts +19 -0
  109. package/dist/providers/base.d.ts.map +1 -0
  110. package/dist/providers/base.js +13 -0
  111. package/dist/providers/base.js.map +1 -0
  112. package/dist/providers/fake.d.ts +98 -0
  113. package/dist/providers/fake.d.ts.map +1 -0
  114. package/dist/providers/fake.js +181 -0
  115. package/dist/providers/fake.js.map +1 -0
  116. package/dist/providers/http.d.ts +62 -0
  117. package/dist/providers/http.d.ts.map +1 -0
  118. package/dist/providers/http.js +245 -0
  119. package/dist/providers/http.js.map +1 -0
  120. package/dist/retrieval/chunking.d.ts +88 -0
  121. package/dist/retrieval/chunking.d.ts.map +1 -0
  122. package/dist/retrieval/chunking.js +188 -0
  123. package/dist/retrieval/chunking.js.map +1 -0
  124. package/dist/retrieval/citations.d.ts +98 -0
  125. package/dist/retrieval/citations.d.ts.map +1 -0
  126. package/dist/retrieval/citations.js +134 -0
  127. package/dist/retrieval/citations.js.map +1 -0
  128. package/dist/retrieval/connectors.d.ts +74 -0
  129. package/dist/retrieval/connectors.d.ts.map +1 -0
  130. package/dist/retrieval/connectors.js +218 -0
  131. package/dist/retrieval/connectors.js.map +1 -0
  132. package/dist/retrieval/embedding.d.ts +116 -0
  133. package/dist/retrieval/embedding.d.ts.map +1 -0
  134. package/dist/retrieval/embedding.js +282 -0
  135. package/dist/retrieval/embedding.js.map +1 -0
  136. package/dist/retrieval/gate.d.ts +52 -0
  137. package/dist/retrieval/gate.d.ts.map +1 -0
  138. package/dist/retrieval/gate.js +91 -0
  139. package/dist/retrieval/gate.js.map +1 -0
  140. package/dist/retrieval/hybrid.d.ts +76 -0
  141. package/dist/retrieval/hybrid.d.ts.map +1 -0
  142. package/dist/retrieval/hybrid.js +150 -0
  143. package/dist/retrieval/hybrid.js.map +1 -0
  144. package/dist/retrieval/metrics.d.ts +126 -0
  145. package/dist/retrieval/metrics.d.ts.map +1 -0
  146. package/dist/retrieval/metrics.js +200 -0
  147. package/dist/retrieval/metrics.js.map +1 -0
  148. package/dist/retrieval/pgvector.d.ts +62 -0
  149. package/dist/retrieval/pgvector.d.ts.map +1 -0
  150. package/dist/retrieval/pgvector.js +262 -0
  151. package/dist/retrieval/pgvector.js.map +1 -0
  152. package/dist/retrieval/rerank.d.ts +61 -0
  153. package/dist/retrieval/rerank.d.ts.map +1 -0
  154. package/dist/retrieval/rerank.js +105 -0
  155. package/dist/retrieval/rerank.js.map +1 -0
  156. package/dist/retrieval/retriever.d.ts +125 -0
  157. package/dist/retrieval/retriever.d.ts.map +1 -0
  158. package/dist/retrieval/retriever.js +281 -0
  159. package/dist/retrieval/retriever.js.map +1 -0
  160. package/dist/retrieval/stores.d.ts +106 -0
  161. package/dist/retrieval/stores.d.ts.map +1 -0
  162. package/dist/retrieval/stores.js +142 -0
  163. package/dist/retrieval/stores.js.map +1 -0
  164. package/dist/retrieval/types.d.ts +314 -0
  165. package/dist/retrieval/types.d.ts.map +1 -0
  166. package/dist/retrieval/types.js +388 -0
  167. package/dist/retrieval/types.js.map +1 -0
  168. package/dist/steps.d.ts +156 -0
  169. package/dist/steps.d.ts.map +1 -0
  170. package/dist/steps.js +199 -0
  171. package/dist/steps.js.map +1 -0
  172. package/dist/structured.d.ts +91 -0
  173. package/dist/structured.d.ts.map +1 -0
  174. package/dist/structured.js +155 -0
  175. package/dist/structured.js.map +1 -0
  176. package/dist/tools.d.ts +100 -0
  177. package/dist/tools.d.ts.map +1 -0
  178. package/dist/tools.js +201 -0
  179. package/dist/tools.js.map +1 -0
  180. package/dist/tracing.d.ts +104 -0
  181. package/dist/tracing.d.ts.map +1 -0
  182. package/dist/tracing.js +155 -0
  183. package/dist/tracing.js.map +1 -0
  184. package/dist/types.d.ts +240 -0
  185. package/dist/types.d.ts.map +1 -0
  186. package/dist/types.js +357 -0
  187. package/dist/types.js.map +1 -0
  188. package/package.json +80 -14
package/dist/steps.js ADDED
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Leaf pipeline steps: `generate`, `retrieve`, `tool` and `emit`.
3
+ *
4
+ * `pipeline.ts` runs steps and `control.ts` composes them; this module is the third
5
+ * part of the family and builds the leaves a pipeline actually reaches the outside
6
+ * world with. Each factory returns an ordinary {@link CompositeStep}, so a leaf
7
+ * composes with a composite by the same rule.
8
+ *
9
+ * Why these exist at all: a generated application inlines its steps as hand-written
10
+ * async functions, which leaves a caller who is *not* the generator -- a test, a
11
+ * conformance runner, a hand-built pipeline -- with no way to drive one step kind
12
+ * without re-writing the primitive's call and its binding rule. That duplication is
13
+ * where the two disagree. A step here is the same primitive the generator calls:
14
+ *
15
+ * - `retrieve` calls {@link RetrieverSeam.retrieve} and binds the `RetrievalResult`.
16
+ * - `tool` calls {@link ToolExecutor.execute} and binds what the tool returned,
17
+ * refusing an error outcome and parsing the content.
18
+ * - `generate` renders a prompt, calls {@link ModelGateway.generate}, and runs the
19
+ * structured path when the caller names an output type.
20
+ * - `emit` projects the context into the event fields a caller names.
21
+ *
22
+ * Every factory takes its inputs **already resolved**: the query string, the argument
23
+ * mapping, the prompt values. Interpolating a spec template against the context is the
24
+ * *emitted step body's* job, and a second implementation of it here would be a second
25
+ * thing to keep in step with the generator's. What is not duplicated is the part that
26
+ * is the same for every caller: the primitive call, the error contract, the parse, and
27
+ * the name the result is bound under.
28
+ *
29
+ * `emit` is the one leaf whose whole behaviour is reading the context, so
30
+ * {@link resolveSource} lives here rather than in a caller: a field's source is a
31
+ * binding name, optionally followed by one attribute, which is exactly the reference
32
+ * path the generator derives for the same field.
33
+ */
34
+ import { PipelineError } from './errors.js';
35
+ import { repr } from './internal/json.js';
36
+ import { parseStructured, runStructured } from './structured.js';
37
+ import { CompletionRequest, Message, ToolCall } from './types.js';
38
+ /**
39
+ * The context key an `emit` step binds its projected payload under.
40
+ *
41
+ * Deliberately *not* in `RESERVED_KEYS`. That set is mirrored in the generator and
42
+ * pinned against the runtime by a generator test, so a seventh entry would have to be
43
+ * emitted as well -- and the generated applications do not compose their response
44
+ * through this step yet. A generated route keeps building its event object itself;
45
+ * adding the key here would reserve a spec name for a step the emitted apps never
46
+ * call. {@link emitStep} takes the key as an option so the generator can adopt it
47
+ * under its own name when it does.
48
+ */
49
+ export const EMITTED_KEY = 'emitted';
50
+ /**
51
+ * Name a step's callable, so a trace and {@link Pipeline.of} identify it.
52
+ *
53
+ * `Pipeline.of` reads `step.name`, so this is the same mechanism as Python assigning
54
+ * `__name__` -- the two runtimes name a leaf identically rather than one of them
55
+ * requiring an explicit name at construction.
56
+ */
57
+ function named(step, name) {
58
+ if (name !== undefined) {
59
+ Object.defineProperty(step, 'name', { value: name, configurable: true });
60
+ }
61
+ return step;
62
+ }
63
+ /**
64
+ * One `emit` field's value: a binding, then at most one attribute below it.
65
+ *
66
+ * The one-segment form is the request event's or a scalar binding's whole value; the
67
+ * two-segment form is a struct's field. Deeper paths are not accepted, because the
68
+ * spec layer's reference paths stop at one field and this resolver exists to read
69
+ * exactly what the generator reads.
70
+ *
71
+ * A missing binding is a {@link PipelineError} naming the key -- the same refusal
72
+ * {@link PipelineContext.require} makes -- and a missing attribute is one naming both
73
+ * the source and the field, because "the field is not there" and "the binding is not
74
+ * there" are different mistakes and both mean the response would be wrong.
75
+ */
76
+ export function resolveSource(context, source) {
77
+ const dot = source.indexOf('.');
78
+ const root = dot === -1 ? source : source.slice(0, dot);
79
+ const attribute = dot === -1 ? '' : source.slice(dot + 1);
80
+ const value = context.require(root);
81
+ if (attribute === '')
82
+ return value;
83
+ if (attribute.includes('.')) {
84
+ throw new PipelineError(`emit source ${repr(source)} names more than one attribute below ${repr(root)}; ` +
85
+ 'a field is read from a binding or one struct below it');
86
+ }
87
+ // An *own* property: that is where a declared field lands both in an object parsed
88
+ // from JSON and in a class that assigns its fields, and it keeps `toString` and
89
+ // `constructor` from reading as fields of every struct.
90
+ const fields = value;
91
+ if (typeof value !== 'object' || fields === null || !Object.hasOwn(fields, attribute)) {
92
+ throw new PipelineError(`emit source ${repr(source)} names the field ${repr(attribute)}, which the ` +
93
+ `${repr(root)} binding does not carry`);
94
+ }
95
+ return fields[attribute];
96
+ }
97
+ /**
98
+ * Build the event payload from the context, field by field.
99
+ *
100
+ * `fields` maps each event field to its source, in the order the caller declared
101
+ * them: an insertion-ordered mapping keeps the payload's own order stable, so a
102
+ * projection that reorders its fields is observable rather than invisible. Each source
103
+ * is a binding name or a `binding.attribute` path, which is the shape the generator
104
+ * derives for the same field via `responsePlan`.
105
+ *
106
+ * The step **binds** its payload and does not stop the pipeline. Stopping would lose
107
+ * it: both runtimes carry the *pre-step* context out of a stop, so a stopping step
108
+ * cannot bind anything. A generated route does not stop at its emit either -- it runs
109
+ * every step and only then builds the response object -- so a later step still runs
110
+ * after this one, which is the behaviour a pipeline that composed it would see.
111
+ */
112
+ export function emitStep(fields, options = {}) {
113
+ const key = options.key ?? EMITTED_KEY;
114
+ const ordered = Object.entries(fields);
115
+ return named(async (context) => {
116
+ const payload = {};
117
+ for (const [field, source] of ordered)
118
+ payload[field] = resolveSource(context, source);
119
+ return context.withValues({ [key]: payload });
120
+ }, options.name);
121
+ }
122
+ /**
123
+ * Search `retriever` and bind the cited passages under `binding`.
124
+ *
125
+ * `topK` is passed through rather than resolved here, so `undefined` keeps meaning
126
+ * "the binding's own ceiling" exactly as `Retriever.retrieve` defines it.
127
+ */
128
+ export function retrieveStep(retriever, options) {
129
+ return named(async (context) => {
130
+ const found = await retriever.retrieve(options.query, {
131
+ topK: options.topK,
132
+ });
133
+ return context.withValues({ [options.binding]: found });
134
+ }, options.name);
135
+ }
136
+ /**
137
+ * Call `tool` and bind what it returned, refusing an error outcome.
138
+ *
139
+ * The call id is the binding name, which makes a trace of a tool step name the value
140
+ * it produced. An error outcome throws rather than binding a message: a tool the model
141
+ * called and that failed is not a value the next step can meaningfully read, and the
142
+ * generator's own step throws for the same reason.
143
+ *
144
+ * `output` is the struct to parse the content into when the spec declared a named
145
+ * output; without one the content is bound as parsed JSON, so a tool declaring
146
+ * `string` binds the string it returned rather than a re-encoded copy.
147
+ */
148
+ export function toolStep(tools, options) {
149
+ return named(async (context) => {
150
+ const outcome = await tools.execute(new ToolCall({
151
+ id: options.binding,
152
+ name: options.tool,
153
+ arguments: { ...options.arguments },
154
+ }));
155
+ if (outcome.isError) {
156
+ throw new PipelineError(`tool ${options.tool} failed: ${outcome.content}`);
157
+ }
158
+ const value = options.output === undefined
159
+ ? JSON.parse(outcome.content)
160
+ : parseStructured(outcome.content, options.output);
161
+ return context.withValues({ [options.binding]: value });
162
+ }, options.name);
163
+ }
164
+ /**
165
+ * Render `prompt`, ask `model` for one completion, and bind the answer.
166
+ *
167
+ * The call is built once and handed to the structured path as its `call`, so a repair
168
+ * round re-sends an already-rendered prompt instead of rendering again -- the same
169
+ * closure the generated step emits, and the reason a retry cannot silently re-read a
170
+ * binding that changed underneath it.
171
+ *
172
+ * `values` are the prompt's own values and are passed to the registry unrendered:
173
+ * {@link PromptRegistry.render} is the one place a template becomes text. With
174
+ * `structured` the answer is parsed into that type, and a parse failure throws after
175
+ * the repair rounds rather than binding a half-valid object.
176
+ */
177
+ export function generateStep(gateway, prompts, options) {
178
+ return named(async (context) => {
179
+ const rendered = prompts.render(options.prompt, options.values ?? {}, options.version);
180
+ const call = async (text) => {
181
+ const request = options.temperature === undefined && options.maxOutputTokens === undefined
182
+ ? CompletionRequest.prompt(text)
183
+ : new CompletionRequest({
184
+ messages: [Message.user(text)],
185
+ temperature: options.temperature,
186
+ maxOutputTokens: options.maxOutputTokens,
187
+ });
188
+ const response = await gateway.generate(options.model, request, {
189
+ fallbacks: options.fallbacks ?? [],
190
+ });
191
+ return response.text;
192
+ };
193
+ const value = options.structured === undefined
194
+ ? await call(rendered.text)
195
+ : await runStructured(call, options.structured, rendered.text);
196
+ return context.withValues({ [options.binding]: value });
197
+ }, options.name);
198
+ }
199
+ //# sourceMappingURL=steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.js","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Structured-output enforcement with a parse-repair loop.
3
+ *
4
+ * This is the only place zod is used, and it is used for what it is good at: getting
5
+ * a typed object out of an untrusted model response. Pipeline control flow is plain
6
+ * async; zod is a validation dependency here, not an orchestration one.
7
+ *
8
+ * Two entry points:
9
+ *
10
+ * - {@link parseStructured} coerces already-received text into a typed value.
11
+ * - {@link runStructured} drives a call-repair-retry loop, feeding the validation
12
+ * failure back to the model. This is the difference between "the model must be
13
+ * right the first time" and "the model must eventually be right", and only the
14
+ * second is an achievable contract.
15
+ */
16
+ import { z } from 'zod';
17
+ import { StructuredOutputError } from './errors.js';
18
+ /** The correction turn appended after a failed parse. */
19
+ export declare const REPAIR_INSTRUCTION: string;
20
+ /**
21
+ * A named output schema.
22
+ *
23
+ * The name exists because Python's reference implementation reads
24
+ * `output_type.__name__` and every diagnostic it produces names the type. A zod
25
+ * schema has no runtime name, so the name is carried alongside it rather than
26
+ * inferred.
27
+ */
28
+ export interface StructuredOutput<T> {
29
+ readonly name: string;
30
+ readonly schema: z.ZodType<T>;
31
+ }
32
+ /** Name a schema so diagnostics can say which type failed. */
33
+ export declare function structuredOutput<T>(name: string, schema: z.ZodType<T>): StructuredOutput<T>;
34
+ /** The members of a zod issue this module reads. */
35
+ interface Issue {
36
+ readonly path: readonly PropertyKey[];
37
+ readonly message: string;
38
+ }
39
+ /** Flatten validation issues into `location: message` strings. */
40
+ export declare function formatProblems(issues: readonly Issue[]): string[];
41
+ /**
42
+ * Validate `text` as `outputType`.
43
+ *
44
+ * Every problem is reported, not just the first: feeding one error back at a time
45
+ * turns a two-round repair into a five-round one.
46
+ */
47
+ export declare function parseStructured<T>(text: string, outputType: StructuredOutput<T>): T;
48
+ /**
49
+ * Call, parse, and on failure ask again with the validation errors attached.
50
+ *
51
+ * `retries` counts *repair* attempts beyond the first call, so `retries: 2` means at
52
+ * most three calls. Throwing after the final attempt is correct: an endpoint that
53
+ * returns a half-valid object is worse than one that fails loudly.
54
+ */
55
+ export declare function runStructured<T>(call: (prompt: string) => Promise<string>, outputType: StructuredOutput<T>, prompt: string, options?: {
56
+ readonly retries?: number;
57
+ }): Promise<T>;
58
+ /** The corrective turn for a failed parse. */
59
+ export declare function repairPrompt(error: StructuredOutputError): string;
60
+ /** The seam a `buildAgent` caller supplies: one prompt in, one model answer out. */
61
+ export interface AgentModel {
62
+ complete(prompt: string): Promise<string>;
63
+ }
64
+ /** A typed agent: `run` drives the repair loop and returns the parsed value. */
65
+ export declare class StructuredAgent<T> {
66
+ private readonly _model;
67
+ private readonly _outputType;
68
+ private readonly _systemPrompt;
69
+ private readonly _retries;
70
+ constructor(model: AgentModel, outputType: StructuredOutput<T>, options?: {
71
+ readonly systemPrompt?: string;
72
+ readonly retries?: number;
73
+ });
74
+ /** Run one prompt through the model, repairing until the schema validates. */
75
+ run(prompt: string): Promise<T>;
76
+ }
77
+ /**
78
+ * Build a typed agent over `outputType`.
79
+ *
80
+ * The reference runtime delegates this to Pydantic AI's `Agent`. The TypeScript
81
+ * runtime has no equivalent, so this is the same contract implemented against the
82
+ * repair loop above -- typed output with retries -- rather than a new orchestration
83
+ * layer.
84
+ */
85
+ export declare function buildAgent<T>(model: AgentModel, outputType: StructuredOutput<T>, options?: {
86
+ readonly systemPrompt?: string;
87
+ readonly retries?: number;
88
+ }): StructuredAgent<T>;
89
+ /** Re-export zod so generated code can declare schemas without a second dependency. */
90
+ export { z };
91
+ //# sourceMappingURL=structured.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured.d.ts","sourceRoot":"","sources":["../src/structured.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,QAE6B,CAAC;AAE7D;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CAC/B;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAG3F;AAED,oDAAoD;AACpD,UAAU,KAAK;IACb,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,EAAE,CAKjE;AA0BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAqBnF;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,EACzC,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1C,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAGjE;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,gFAAgF;AAChF,qBAAa,eAAe,CAAC,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsB;IAClD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqB;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAElC,YACE,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,OAAO,GAAE;QAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,EAM5E;IAED,8EAA8E;IACxE,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAMpC;CACF;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC/B,OAAO,GAAE;IAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAC1E,eAAe,CAAC,CAAC,CAAC,CAEpB;AAED,uFAAuF;AACvF,OAAO,EAAE,CAAC,EAAE,CAAC"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Structured-output enforcement with a parse-repair loop.
3
+ *
4
+ * This is the only place zod is used, and it is used for what it is good at: getting
5
+ * a typed object out of an untrusted model response. Pipeline control flow is plain
6
+ * async; zod is a validation dependency here, not an orchestration one.
7
+ *
8
+ * Two entry points:
9
+ *
10
+ * - {@link parseStructured} coerces already-received text into a typed value.
11
+ * - {@link runStructured} drives a call-repair-retry loop, feeding the validation
12
+ * failure back to the model. This is the difference between "the model must be
13
+ * right the first time" and "the model must eventually be right", and only the
14
+ * second is an achievable contract.
15
+ */
16
+ import { z } from 'zod';
17
+ import { StructuredOutputError } from './errors.js';
18
+ /** The correction turn appended after a failed parse. */
19
+ export const REPAIR_INSTRUCTION = 'Your previous response could not be parsed. Reply with corrected JSON only, ' +
20
+ 'matching the required schema exactly. Errors: {problems}';
21
+ /** Name a schema so diagnostics can say which type failed. */
22
+ export function structuredOutput(name, schema) {
23
+ if (name.length === 0)
24
+ throw new RangeError('a structured output type needs a name');
25
+ return { name, schema };
26
+ }
27
+ /** Flatten validation issues into `location: message` strings. */
28
+ export function formatProblems(issues) {
29
+ return issues.map((issue) => {
30
+ const location = issue.path.map((part) => String(part)).join('.') || '<root>';
31
+ return `${location}: ${issue.message}`;
32
+ });
33
+ }
34
+ /**
35
+ * Remove a ```json fence if the model wrapped its answer in one.
36
+ *
37
+ * Models do this constantly when asked for JSON. Treating a valid payload as invalid
38
+ * because of presentation is a self-inflicted repair loop.
39
+ */
40
+ function stripCodeFence(text) {
41
+ const stripped = text.trim();
42
+ if (!stripped.startsWith('```'))
43
+ return stripped;
44
+ const lines = stripped.split('\n');
45
+ if (lines.length < 2)
46
+ return stripped;
47
+ const body = lines.slice(1);
48
+ const last = body.at(-1);
49
+ if (last?.trim().startsWith('```'))
50
+ body.pop();
51
+ return body.join('\n');
52
+ }
53
+ function invalidJson(outputType) {
54
+ return new StructuredOutputError(`output did not validate as ${outputType.name}`, {
55
+ attempts: 1,
56
+ problems: ['<root>: invalid JSON'],
57
+ });
58
+ }
59
+ /**
60
+ * Validate `text` as `outputType`.
61
+ *
62
+ * Every problem is reported, not just the first: feeding one error back at a time
63
+ * turns a two-round repair into a five-round one.
64
+ */
65
+ export function parseStructured(text, outputType) {
66
+ const stripped = stripCodeFence(text).trim();
67
+ if (stripped.length === 0) {
68
+ throw new StructuredOutputError(`model returned empty output for ${outputType.name}`, {
69
+ attempts: 1,
70
+ });
71
+ }
72
+ let parsed;
73
+ try {
74
+ parsed = JSON.parse(stripped);
75
+ }
76
+ catch {
77
+ throw invalidJson(outputType);
78
+ }
79
+ const result = outputType.schema.safeParse(parsed);
80
+ if (!result.success) {
81
+ throw new StructuredOutputError(`output did not validate as ${outputType.name}`, {
82
+ attempts: 1,
83
+ problems: formatProblems(result.error.issues),
84
+ });
85
+ }
86
+ return result.data;
87
+ }
88
+ /**
89
+ * Call, parse, and on failure ask again with the validation errors attached.
90
+ *
91
+ * `retries` counts *repair* attempts beyond the first call, so `retries: 2` means at
92
+ * most three calls. Throwing after the final attempt is correct: an endpoint that
93
+ * returns a half-valid object is worse than one that fails loudly.
94
+ */
95
+ export async function runStructured(call, outputType, prompt, options = {}) {
96
+ const retries = options.retries ?? 2;
97
+ if (retries < 0)
98
+ throw new RangeError('retries must not be negative');
99
+ let current = prompt;
100
+ let problems = [];
101
+ for (let attempt = 1; attempt <= retries + 1; attempt += 1) {
102
+ const text = await call(current);
103
+ try {
104
+ return parseStructured(text, outputType);
105
+ }
106
+ catch (error) {
107
+ if (!(error instanceof StructuredOutputError))
108
+ throw error;
109
+ problems = [...error.problems];
110
+ if (attempt <= retries) {
111
+ current = `${prompt}\n\n${repairPrompt(error)}`;
112
+ }
113
+ }
114
+ }
115
+ throw new StructuredOutputError(`${outputType.name} not produced from ${retries + 1} attempt(s)`, { attempts: retries + 1, problems });
116
+ }
117
+ /** The corrective turn for a failed parse. */
118
+ export function repairPrompt(error) {
119
+ const problems = error.problems.length > 0 ? error.problems.join('; ') : error.message;
120
+ return REPAIR_INSTRUCTION.replace('{problems}', () => problems);
121
+ }
122
+ /** A typed agent: `run` drives the repair loop and returns the parsed value. */
123
+ export class StructuredAgent {
124
+ _model;
125
+ _outputType;
126
+ _systemPrompt;
127
+ _retries;
128
+ constructor(model, outputType, options = {}) {
129
+ this._model = model;
130
+ this._outputType = outputType;
131
+ this._systemPrompt = options.systemPrompt;
132
+ this._retries = options.retries ?? 2;
133
+ }
134
+ /** Run one prompt through the model, repairing until the schema validates. */
135
+ async run(prompt) {
136
+ const composed = this._systemPrompt === undefined ? prompt : `${this._systemPrompt}\n\n${prompt}`;
137
+ return runStructured((current) => this._model.complete(current), this._outputType, composed, {
138
+ retries: this._retries,
139
+ });
140
+ }
141
+ }
142
+ /**
143
+ * Build a typed agent over `outputType`.
144
+ *
145
+ * The reference runtime delegates this to Pydantic AI's `Agent`. The TypeScript
146
+ * runtime has no equivalent, so this is the same contract implemented against the
147
+ * repair loop above -- typed output with retries -- rather than a new orchestration
148
+ * layer.
149
+ */
150
+ export function buildAgent(model, outputType, options = {}) {
151
+ return new StructuredAgent(model, outputType, options);
152
+ }
153
+ /** Re-export zod so generated code can declare schemas without a second dependency. */
154
+ export { z };
155
+ //# sourceMappingURL=structured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured.js","sourceRoot":"","sources":["../src/structured.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Tool dispatch with schema validation.
3
+ *
4
+ * The one place this module cannot mirror the reference runtime is the seam itself:
5
+ * Python infers a tool's JSON schema from `inspect.signature` and a docstring, and
6
+ * JavaScript has neither. So the schema is declared explicitly and validated against
7
+ * the tool set here instead -- the runtime's job is to refuse a *wrong* invocation,
8
+ * and that job is identical either way.
9
+ *
10
+ * The validator implements a deliberate subset of JSON Schema: `type`, `required`
11
+ * and `additionalProperties: false`. That subset is documented rather than silently
12
+ * partial, and an unknown `type` value is treated as unconstrained instead of
13
+ * failing, because a schema written for a newer draft must not reject every call.
14
+ */
15
+ import type { ConcurrencyLimiter } from './concurrency.js';
16
+ import { type ToolCall, ToolDefinition, ToolResult } from './types.js';
17
+ /** A handler receives validated arguments and may return anything serialisable. */
18
+ export type ToolHandler = (args: Record<string, unknown>) => unknown | Promise<unknown>;
19
+ /** The JSON-Schema subset this validator enforces. */
20
+ export interface ToolParameters {
21
+ readonly type?: string;
22
+ readonly properties?: Readonly<Record<string, {
23
+ readonly type?: string;
24
+ }>>;
25
+ readonly required?: readonly string[];
26
+ readonly additionalProperties?: boolean;
27
+ }
28
+ /** A registered tool: its public definition plus the code behind it. */
29
+ export declare class Tool {
30
+ readonly definition_: ToolDefinition;
31
+ readonly handler: ToolHandler;
32
+ constructor(init: {
33
+ readonly name: string;
34
+ readonly handler: ToolHandler;
35
+ readonly description?: string;
36
+ readonly parameters?: ToolParameters;
37
+ });
38
+ /**
39
+ * Declare a tool.
40
+ *
41
+ * `parameters` is required where Python would infer it. A schema whose `required`
42
+ * list names a property it does not define is a wiring mistake, and it is reported
43
+ * here rather than at the first call: that is the same failure Python reports as
44
+ * "not accepted by the handler", just discovered from the other direction.
45
+ */
46
+ static of(init: {
47
+ readonly name: string;
48
+ readonly handler: ToolHandler;
49
+ readonly description?: string;
50
+ readonly parameters?: ToolParameters;
51
+ }): Tool;
52
+ get name(): string;
53
+ get definition(): ToolDefinition;
54
+ private checkSchema;
55
+ }
56
+ /**
57
+ * Validate `args` against `schema`, returning every problem rather than the first.
58
+ *
59
+ * Returning all problems is what makes a single repair turn enough: a model told
60
+ * about one bad field per round trips once per field.
61
+ */
62
+ export declare function validateArguments(schema: ToolParameters, args: unknown): string[];
63
+ /**
64
+ * A set of tools, and the dispatcher for them.
65
+ *
66
+ * `strict` decides what a crashing handler means. The default is to hand the model
67
+ * an error result so it can react; strict mode rethrows, because a caller that has
68
+ * already decided a crash is a bug should not have to inspect a result to find out.
69
+ */
70
+ export declare class ToolExecutor {
71
+ private readonly _tools;
72
+ private readonly _strict;
73
+ private readonly _limiter;
74
+ constructor(tools?: Iterable<Tool>, options?: {
75
+ readonly strict?: boolean;
76
+ readonly limiter?: ConcurrencyLimiter;
77
+ });
78
+ /** The registered names, sorted. */
79
+ names(): string[];
80
+ /** Add a tool. A duplicate name replaces, because a registry is a map. */
81
+ register(tool: Tool): void;
82
+ /** One tool's public definition. */
83
+ definition(name: string): ToolDefinition;
84
+ /** Every registered definition, ordered by name. */
85
+ definitions(): ToolDefinition[];
86
+ /** Whether a name is registered. */
87
+ has(name: string): boolean;
88
+ /**
89
+ * Run one call.
90
+ *
91
+ * An unknown tool throws: that is a wiring error in generated code, not something
92
+ * a model can fix by trying again with the same name.
93
+ */
94
+ execute(call: ToolCall): Promise<ToolResult>;
95
+ private dispatch;
96
+ /** Run calls in order. Sequential on purpose: a tool set is a transcript, not a race. */
97
+ executeAll(calls: Iterable<ToolCall>): Promise<ToolResult[]>;
98
+ private require;
99
+ }
100
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}