@maxanstey-meridian/tandem 0.1.0-alpha.1 → 0.1.2

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 (116) hide show
  1. package/dist/index.d.ts +57 -14
  2. package/dist/index.js +134 -79
  3. package/dist/runtime/FluentValidation.dll +0 -0
  4. package/dist/runtime/Google.Protobuf.dll +0 -0
  5. package/dist/runtime/Microsoft.Agents.AI.Abstractions.dll +0 -0
  6. package/dist/runtime/Microsoft.Agents.AI.Harness.dll +0 -0
  7. package/dist/runtime/Microsoft.Agents.AI.Tools.Shell.dll +0 -0
  8. package/dist/runtime/Microsoft.Agents.AI.Workflows.dll +0 -0
  9. package/dist/runtime/Microsoft.Agents.AI.dll +0 -0
  10. package/dist/runtime/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  11. package/dist/runtime/Microsoft.CodeAnalysis.dll +0 -0
  12. package/dist/runtime/Microsoft.Data.Sqlite.dll +0 -0
  13. package/dist/runtime/Microsoft.Extensions.AI.Abstractions.dll +0 -0
  14. package/dist/runtime/Microsoft.Extensions.AI.Evaluation.dll +0 -0
  15. package/dist/runtime/Microsoft.Extensions.AI.OpenAI.dll +0 -0
  16. package/dist/runtime/Microsoft.Extensions.AI.dll +0 -0
  17. package/dist/runtime/Microsoft.Extensions.Caching.Abstractions.dll +0 -0
  18. package/dist/runtime/Microsoft.Extensions.Compliance.Abstractions.dll +0 -0
  19. package/dist/runtime/Microsoft.Extensions.Configuration.Abstractions.dll +0 -0
  20. package/dist/runtime/Microsoft.Extensions.DependencyInjection.Abstractions.dll +0 -0
  21. package/dist/runtime/Microsoft.Extensions.Diagnostics.Abstractions.dll +0 -0
  22. package/dist/runtime/Microsoft.Extensions.FileProviders.Abstractions.dll +0 -0
  23. package/dist/runtime/Microsoft.Extensions.FileSystemGlobbing.dll +0 -0
  24. package/dist/runtime/Microsoft.Extensions.Hosting.Abstractions.dll +0 -0
  25. package/dist/runtime/Microsoft.Extensions.Logging.Abstractions.dll +0 -0
  26. package/dist/runtime/Microsoft.Extensions.ObjectPool.dll +0 -0
  27. package/dist/runtime/Microsoft.Extensions.Options.dll +0 -0
  28. package/dist/runtime/Microsoft.Extensions.Primitives.dll +0 -0
  29. package/dist/runtime/Microsoft.Extensions.VectorData.Abstractions.dll +0 -0
  30. package/dist/runtime/Microsoft.JavaScript.NodeApi.dll +0 -0
  31. package/dist/runtime/Microsoft.ML.Tokenizers.dll +0 -0
  32. package/dist/runtime/OpenAI.dll +0 -0
  33. package/dist/runtime/OpenTelemetry.Api.dll +0 -0
  34. package/dist/runtime/SQLitePCLRaw.batteries_v2.dll +0 -0
  35. package/dist/runtime/SQLitePCLRaw.core.dll +0 -0
  36. package/dist/runtime/SQLitePCLRaw.provider.e_sqlite3.dll +0 -0
  37. package/dist/runtime/Spectre.Console.Ansi.dll +0 -0
  38. package/dist/runtime/Spectre.Console.dll +0 -0
  39. package/dist/runtime/System.ClientModel.dll +0 -0
  40. package/dist/runtime/System.Memory.Data.dll +0 -0
  41. package/dist/runtime/System.Numerics.Tensors.dll +0 -0
  42. package/dist/runtime/System.Reflection.MetadataLoadContext.dll +0 -0
  43. package/dist/runtime/Tandem.Advanced.dll +0 -0
  44. package/dist/runtime/Tandem.Ledger.dll +0 -0
  45. package/dist/runtime/Tandem.NodeApiSpike.Bridge.cjs +26 -0
  46. package/dist/runtime/Tandem.NodeApiSpike.Bridge.d.ts +23 -0
  47. package/dist/runtime/Tandem.NodeApiSpike.Bridge.deps.json +1097 -0
  48. package/dist/runtime/Tandem.NodeApiSpike.Bridge.dll +0 -0
  49. package/dist/runtime/Tandem.NodeApiSpike.Bridge.mjs +31 -0
  50. package/dist/runtime/Tandem.NodeApiSpike.Bridge.runtimeconfig.json +13 -0
  51. package/dist/runtime/Tandem.OpenAICompatible.dll +0 -0
  52. package/dist/runtime/Tandem.Terminal.dll +0 -0
  53. package/dist/runtime/Tandem.dll +0 -0
  54. package/dist/runtime/libe_sqlite3.dylib +0 -0
  55. package/dist/runtime/loader.d.mts +10 -0
  56. package/dist/runtime/loader.mjs +35 -0
  57. package/package.json +20 -6
  58. package/runtime/FluentValidation.dll +0 -0
  59. package/runtime/Google.Protobuf.dll +0 -0
  60. package/runtime/Microsoft.Agents.AI.Abstractions.dll +0 -0
  61. package/runtime/Microsoft.Agents.AI.Harness.dll +0 -0
  62. package/runtime/Microsoft.Agents.AI.Tools.Shell.dll +0 -0
  63. package/runtime/Microsoft.Agents.AI.Workflows.dll +0 -0
  64. package/runtime/Microsoft.Agents.AI.dll +0 -0
  65. package/runtime/Microsoft.CodeAnalysis.CSharp.dll +0 -0
  66. package/runtime/Microsoft.CodeAnalysis.dll +0 -0
  67. package/runtime/Microsoft.Data.Sqlite.dll +0 -0
  68. package/runtime/Microsoft.Extensions.AI.Abstractions.dll +0 -0
  69. package/runtime/Microsoft.Extensions.AI.Evaluation.dll +0 -0
  70. package/runtime/Microsoft.Extensions.AI.OpenAI.dll +0 -0
  71. package/runtime/Microsoft.Extensions.AI.dll +0 -0
  72. package/runtime/Microsoft.Extensions.Caching.Abstractions.dll +0 -0
  73. package/runtime/Microsoft.Extensions.Compliance.Abstractions.dll +0 -0
  74. package/runtime/Microsoft.Extensions.Configuration.Abstractions.dll +0 -0
  75. package/runtime/Microsoft.Extensions.DependencyInjection.Abstractions.dll +0 -0
  76. package/runtime/Microsoft.Extensions.Diagnostics.Abstractions.dll +0 -0
  77. package/runtime/Microsoft.Extensions.FileProviders.Abstractions.dll +0 -0
  78. package/runtime/Microsoft.Extensions.FileSystemGlobbing.dll +0 -0
  79. package/runtime/Microsoft.Extensions.Hosting.Abstractions.dll +0 -0
  80. package/runtime/Microsoft.Extensions.Logging.Abstractions.dll +0 -0
  81. package/runtime/Microsoft.Extensions.ObjectPool.dll +0 -0
  82. package/runtime/Microsoft.Extensions.Options.dll +0 -0
  83. package/runtime/Microsoft.Extensions.Primitives.dll +0 -0
  84. package/runtime/Microsoft.Extensions.VectorData.Abstractions.dll +0 -0
  85. package/runtime/Microsoft.JavaScript.NodeApi.dll +0 -0
  86. package/runtime/Microsoft.ML.Tokenizers.dll +0 -0
  87. package/runtime/OpenAI.dll +0 -0
  88. package/runtime/OpenTelemetry.Api.dll +0 -0
  89. package/runtime/SQLitePCLRaw.batteries_v2.dll +0 -0
  90. package/runtime/SQLitePCLRaw.core.dll +0 -0
  91. package/runtime/SQLitePCLRaw.provider.e_sqlite3.dll +0 -0
  92. package/runtime/Spectre.Console.Ansi.dll +0 -0
  93. package/runtime/Spectre.Console.dll +0 -0
  94. package/runtime/System.ClientModel.dll +0 -0
  95. package/runtime/System.Memory.Data.dll +0 -0
  96. package/runtime/System.Numerics.Tensors.dll +0 -0
  97. package/runtime/System.Reflection.MetadataLoadContext.dll +0 -0
  98. package/runtime/Tandem.Advanced.dll +0 -0
  99. package/runtime/Tandem.Ledger.dll +0 -0
  100. package/runtime/Tandem.NodeApiSpike.Bridge.cjs +26 -0
  101. package/runtime/Tandem.NodeApiSpike.Bridge.d.ts +23 -0
  102. package/runtime/Tandem.NodeApiSpike.Bridge.deps.json +1097 -0
  103. package/runtime/Tandem.NodeApiSpike.Bridge.dll +0 -0
  104. package/runtime/Tandem.NodeApiSpike.Bridge.mjs +31 -0
  105. package/runtime/Tandem.NodeApiSpike.Bridge.runtimeconfig.json +13 -0
  106. package/runtime/Tandem.OpenAICompatible.dll +0 -0
  107. package/runtime/Tandem.Terminal.dll +0 -0
  108. package/runtime/Tandem.dll +0 -0
  109. package/runtime/libe_sqlite3.dylib +0 -0
  110. package/runtime/loader.d.mts +10 -0
  111. package/runtime/loader.mjs +35 -0
  112. package/scripts/install-runtime.mjs +75 -0
  113. package/src/cli.ts +72 -0
  114. package/src/index.ts +2096 -0
  115. package/src/runtime/loader.d.mts +10 -0
  116. package/tsconfig.json +14 -0
package/dist/index.d.ts CHANGED
@@ -104,6 +104,10 @@ export interface OpenAiCompatibleChatClient {
104
104
  readonly wireApi: "completions" | "responses";
105
105
  readonly apiKeyEnvironmentVariable?: string;
106
106
  readonly verifyModel?: boolean;
107
+ /** Per-attempt transport limits; omitted preserves provider defaults. */
108
+ readonly requestTimeoutMs?: number;
109
+ readonly idleTimeoutMs?: number;
110
+ readonly maxAttempts?: number;
107
111
  }
108
112
  export type ChatClient = OpenAiCompatibleChatClient;
109
113
  export type AgentReasoning = {
@@ -117,24 +121,11 @@ export interface AgentSkill {
117
121
  readonly directory: string;
118
122
  }
119
123
  export type AgentToolName = "read_file" | "ls" | "grep" | "write_file" | "delete_file" | "replace" | "replace_lines" | "git:ro" | "shell" | "web_search" | "web_fetch";
120
- interface AgentCommandArgumentBase {
121
- readonly name: string;
122
- readonly description: string;
123
- readonly flag: string;
124
- readonly maxLength?: number;
125
- }
126
- export type AgentCommandArgument = AgentCommandArgumentBase & ({
127
- readonly pattern: string;
128
- readonly allowedValues?: never;
129
- } | {
130
- readonly allowedValues: readonly string[];
131
- readonly pattern?: never;
132
- });
133
124
  export interface AgentCommand {
134
125
  readonly name: string;
135
126
  readonly description: string;
136
127
  readonly command: string;
137
- readonly arguments?: readonly AgentCommandArgument[];
128
+ readonly arguments?: readonly string[];
138
129
  }
139
130
  interface AgentCommandSelection {
140
131
  readonly [commandSelectionBrand]: object;
@@ -182,6 +173,12 @@ export interface AgentDefinition<TState, TOutput = never> {
182
173
  readonly schema: z.ZodType<TOutput>;
183
174
  readonly validateFor?: (state: TState, output: TOutput) => readonly ValidationProblem[];
184
175
  readonly apply: (state: TState, output: TOutput) => TState;
176
+ } | {
177
+ readonly instructions: string;
178
+ readonly raw: true;
179
+ readonly parse: (response: string) => TOutput;
180
+ readonly validateFor?: (state: TState, output: TOutput) => readonly ValidationProblem[];
181
+ readonly apply: (state: TState, output: TOutput) => TState;
185
182
  };
186
183
  readonly capabilities?: readonly Capability<TState>[];
187
184
  readonly skills?: readonly AgentSkill[];
@@ -211,6 +208,8 @@ type ParallelDefinition<TState, TBranches extends ParallelBranches<TState>> = {
211
208
  readonly merge: (baseline: TState, results: {
212
209
  readonly [K in keyof TBranches]: TState;
213
210
  }) => TState;
211
+ /** Maximum active branches per invocation; omitted means all branches. */
212
+ readonly max?: number;
214
213
  readonly persist?: boolean;
215
214
  };
216
215
  export declare function parallel<TState>(): <const TBranches extends ParallelBranches<TState>>(definition: ParallelDefinition<TState, TBranches>) => Parallel<TState>;
@@ -256,6 +255,48 @@ export declare function pipeline<TState>(definition: {
256
255
  outputs: readonly Terminal<NoInfer<TState>>[];
257
256
  persist?: boolean;
258
257
  }): Pipeline<TState>;
258
+ export interface PipelineInspection {
259
+ readonly name: string;
260
+ readonly stateSchema: unknown;
261
+ readonly start: string;
262
+ readonly persist: boolean;
263
+ readonly nodes: readonly InspectedNode[];
264
+ readonly routes: readonly InspectedRoute[];
265
+ readonly outputs: readonly string[];
266
+ }
267
+ export interface InspectedRoute {
268
+ readonly id: string;
269
+ readonly source: string;
270
+ readonly target: string;
271
+ readonly label: string;
272
+ readonly order: number;
273
+ readonly outcome?: "success" | "failed";
274
+ readonly conditional: boolean;
275
+ }
276
+ export interface InspectedNode {
277
+ readonly id: string;
278
+ readonly kind: "stage" | "interaction" | "agent" | "parallel" | "completion" | "failure";
279
+ readonly persist?: boolean;
280
+ readonly interaction?: {
281
+ readonly requestSchema: unknown;
282
+ readonly responseSchema: unknown;
283
+ };
284
+ readonly agent?: {
285
+ readonly capabilities: readonly {
286
+ readonly name: string;
287
+ readonly requestSchema: unknown;
288
+ }[];
289
+ readonly outputSchema?: unknown;
290
+ readonly workspace: boolean;
291
+ };
292
+ readonly max?: number;
293
+ readonly branches?: readonly {
294
+ readonly id: string;
295
+ readonly participant: InspectedNode;
296
+ }[];
297
+ }
298
+ /** Projects an instantiated pipeline without compiling, registering, or invoking callbacks. */
299
+ export declare function inspectPipeline<TState>(graph: Pipeline<TState>): PipelineInspection;
259
300
  export interface RunResult<TState> {
260
301
  readonly runId: string;
261
302
  readonly succeeded: boolean;
@@ -319,6 +360,8 @@ export interface TerminalPresentationOptions {
319
360
  }
320
361
  export interface RunOptions {
321
362
  readonly ledgerPath?: string;
363
+ /** Expose ledger read/search tools to agents. Disabled by default; does not affect logging. */
364
+ readonly enableLedgerTools?: boolean;
322
365
  readonly signal?: AbortSignal;
323
366
  readonly interactions?: InteractionHandlers;
324
367
  readonly presentation?: "terminal";
package/dist/index.js CHANGED
@@ -494,9 +494,7 @@ function copyAgentCommand(command) {
494
494
  ? { ...command }
495
495
  : {
496
496
  ...command,
497
- arguments: command.arguments.map((argument) => argument.pattern !== undefined
498
- ? { ...argument }
499
- : { ...argument, allowedValues: [...argument.allowedValues] }),
497
+ arguments: [...command.arguments],
500
498
  };
501
499
  }
502
500
  function validateAgentCommands(commands, context) {
@@ -519,65 +517,22 @@ function validateAgentCommands(commands, context) {
519
517
  throw new TandemError(`${commandContext}.command must be non-blank.`);
520
518
  }
521
519
  if (candidate.arguments !== undefined && !Array.isArray(candidate.arguments)) {
522
- throw new TandemError(`${commandContext}.arguments must be an array.`);
520
+ throw new TandemError(`${commandContext}.arguments must be an array of strings.`);
523
521
  }
524
- const argumentNames = new Set();
525
- for (const [argumentIndex, argument] of (candidate.arguments ?? []).entries()) {
522
+ const argumentList = candidate.arguments ?? [];
523
+ if (argumentList.length > 16) {
524
+ throw new TandemError(`${commandContext}.arguments accepts at most 16 arguments.`);
525
+ }
526
+ for (const [argumentIndex, argument] of argumentList.entries()) {
526
527
  const argumentContext = `${commandContext}.arguments[${argumentIndex}]`;
527
- if (typeof argument !== "object" || argument === null) {
528
- throw new TandemError(`${argumentContext} must be an argument.`);
529
- }
530
- const candidateArgument = argument;
531
- if (typeof candidateArgument.name !== "string" ||
532
- !/^[A-Za-z_][A-Za-z0-9_]*$/.test(candidateArgument.name)) {
533
- throw new TandemError(`${argumentContext}.name must be a valid JSON property identifier.`);
534
- }
535
- if (argumentNames.has(candidateArgument.name)) {
536
- throw new TandemError(`${argumentContext}.name duplicates '${candidateArgument.name}'.`);
537
- }
538
- argumentNames.add(candidateArgument.name);
539
- if (typeof candidateArgument.description !== "string" ||
540
- candidateArgument.description.trim().length === 0) {
541
- throw new TandemError(`${argumentContext}.description must be non-blank.`);
542
- }
543
- if (typeof candidateArgument.flag !== "string" ||
544
- candidateArgument.flag.trim().length === 0 ||
545
- /\s/.test(candidateArgument.flag)) {
546
- throw new TandemError(`${argumentContext}.flag must be a whitespace-free switch token.`);
528
+ if (typeof argument !== "string") {
529
+ throw new TandemError(`${argumentContext} must be a string.`);
547
530
  }
548
- if (candidateArgument.pattern !== undefined &&
549
- typeof candidateArgument.pattern !== "string") {
550
- throw new TandemError(`${argumentContext}.pattern must be a string.`);
531
+ if (argument.trim().length === 0) {
532
+ throw new TandemError(`${argumentContext} must not be blank.`);
551
533
  }
552
- if (candidateArgument.allowedValues !== undefined &&
553
- !Array.isArray(candidateArgument.allowedValues)) {
554
- throw new TandemError(`${argumentContext}.allowedValues must be an array.`);
555
- }
556
- const hasPattern = typeof candidateArgument.pattern === "string";
557
- const hasAllowedValues = Array.isArray(candidateArgument.allowedValues);
558
- if (hasPattern === hasAllowedValues) {
559
- throw new TandemError(`${argumentContext} requires exactly one of pattern or allowedValues.`);
560
- }
561
- if (candidateArgument.maxLength !== undefined &&
562
- (!Number.isSafeInteger(candidateArgument.maxLength) ||
563
- candidateArgument.maxLength <= 0 ||
564
- candidateArgument.maxLength > 2_147_483_647)) {
565
- throw new TandemError(`${argumentContext}.maxLength must be a positive integer.`);
566
- }
567
- if (candidateArgument.allowedValues !== undefined) {
568
- if (candidateArgument.allowedValues.length === 0) {
569
- throw new TandemError(`${argumentContext}.allowedValues must not be empty.`);
570
- }
571
- const values = new Set();
572
- for (const value of candidateArgument.allowedValues) {
573
- if (typeof value !== "string" || value.trim().length === 0) {
574
- throw new TandemError(`${argumentContext}.allowedValues must be non-blank strings.`);
575
- }
576
- if (values.has(value)) {
577
- throw new TandemError(`${argumentContext}.allowedValues duplicates '${value}'.`);
578
- }
579
- values.add(value);
580
- }
534
+ if (argument.length > 200) {
535
+ throw new TandemError(`${argumentContext} must be at most 200 characters.`);
581
536
  }
582
537
  }
583
538
  }
@@ -641,6 +596,20 @@ export function agent(definition) {
641
596
  }
642
597
  if (definition.output) {
643
598
  requireInstructions(definition.output.instructions, `Agent '${definition.id}' output instructions`);
599
+ if ("raw" in definition.output) {
600
+ if (definition.output.raw !== true) {
601
+ throw new TandemError(`Agent '${definition.id}' output raw must be true.`);
602
+ }
603
+ if ("schema" in definition.output) {
604
+ throw new TandemError(`Agent '${definition.id}' output schema is forbidden for raw output.`);
605
+ }
606
+ if (typeof definition.output.parse !== "function") {
607
+ throw new TandemError(`Agent '${definition.id}' raw output requires a parse function.`);
608
+ }
609
+ }
610
+ else if ("parse" in definition.output) {
611
+ throw new TandemError(`Agent '${definition.id}' output parse requires raw output mode.`);
612
+ }
644
613
  }
645
614
  const capabilities = definition.capabilities ?? [];
646
615
  const names = new Set();
@@ -710,11 +679,13 @@ export function agent(definition) {
710
679
  }
711
680
  class ParallelImplementation extends NodeImplementation {
712
681
  branches;
682
+ max;
713
683
  merge;
714
684
  kind = "parallel";
715
- constructor(id, persist, branches, merge) {
685
+ constructor(id, persist, branches, max, merge) {
716
686
  super(id, persist);
717
687
  this.branches = branches;
688
+ this.max = max;
718
689
  this.merge = merge;
719
690
  }
720
691
  }
@@ -725,6 +696,10 @@ export function parallel(definition) {
725
696
  return createParallel(definition);
726
697
  }
727
698
  function createParallel(definition) {
699
+ if (definition.max !== undefined &&
700
+ (!Number.isInteger(definition.max) || definition.max < 1 || definition.max > 2147483647)) {
701
+ throw new TandemError(`Parallel group '${definition.id}' max must be a positive 32-bit integer.`);
702
+ }
728
703
  const entries = Object.entries(definition.branches);
729
704
  if (entries.length < 2) {
730
705
  throw new TandemError(`Parallel group '${definition.id}' requires at least two branches.`);
@@ -733,7 +708,7 @@ function createParallel(definition) {
733
708
  if (participants.size !== entries.length) {
734
709
  throw new TandemError(`Parallel group '${definition.id}' must own a distinct participant per branch.`);
735
710
  }
736
- return new ParallelImplementation(definition.id, definition.persist, definition.branches, definition.merge);
711
+ return new ParallelImplementation(definition.id, definition.persist, definition.branches, definition.max, definition.merge);
737
712
  }
738
713
  class TerminalImplementation extends NodeImplementation {
739
714
  failed;
@@ -838,6 +813,78 @@ export function pipeline(definition) {
838
813
  }
839
814
  return { ...definition, persist: definition.persist ?? false };
840
815
  }
816
+ /** Projects an instantiated pipeline without compiling, registering, or invoking callbacks. */
817
+ export function inspectPipeline(graph) {
818
+ const inspectNode = (node) => {
819
+ const implementation = node;
820
+ const persist = implementation.persist;
821
+ if (node.kind === "interaction") {
822
+ const interaction = implementation;
823
+ return {
824
+ id: node.id,
825
+ kind: "interaction",
826
+ persist,
827
+ interaction: {
828
+ requestSchema: z.toJSONSchema(interaction.requestSchema, { io: "input" }),
829
+ responseSchema: z.toJSONSchema(interaction.responseSchema, { io: "input" }),
830
+ },
831
+ };
832
+ }
833
+ if (node.kind === "agent") {
834
+ const agent = implementation;
835
+ return {
836
+ id: node.id,
837
+ kind: "agent",
838
+ persist,
839
+ agent: {
840
+ capabilities: agent.granted.map((item) => ({
841
+ name: item.name,
842
+ requestSchema: JSON.parse(item.requestJsonSchema),
843
+ })),
844
+ ...(!agent.output || "raw" in agent.output
845
+ ? {}
846
+ : { outputSchema: z.toJSONSchema(agent.output.schema, { io: "input" }) }),
847
+ workspace: agent.workspace !== undefined,
848
+ },
849
+ };
850
+ }
851
+ if (node.kind === "parallel") {
852
+ const parallel = implementation;
853
+ return {
854
+ id: node.id,
855
+ kind: "parallel",
856
+ persist,
857
+ ...(parallel.max !== undefined ? { max: parallel.max } : {}),
858
+ branches: Object.entries(parallel.branches).map(([id, participant]) => ({
859
+ id,
860
+ participant: inspectNode(participant),
861
+ })),
862
+ };
863
+ }
864
+ if (node.kind === "terminal") {
865
+ const terminal = implementation;
866
+ return { id: node.id, kind: terminal.failed ? "failure" : "completion", persist };
867
+ }
868
+ return { id: node.id, kind: "stage", persist };
869
+ };
870
+ return {
871
+ name: graph.name,
872
+ stateSchema: z.toJSONSchema(graph.state, { io: "input" }),
873
+ start: graph.start.id,
874
+ persist: graph.persist,
875
+ nodes: graph.nodes.map(inspectNode),
876
+ routes: graph.routes.map((item, order) => ({
877
+ id: `route:${order}`,
878
+ source: item.from.id,
879
+ target: item.to.id,
880
+ label: item.label,
881
+ order,
882
+ ...(item.outcome === undefined ? {} : { outcome: item.outcome }),
883
+ conditional: item.when !== undefined,
884
+ })),
885
+ outputs: graph.outputs.map((item) => item.id),
886
+ };
887
+ }
841
888
  const runObservationSchema = z.discriminatedUnion("kind", [
842
889
  z
843
890
  .object({ version: z.literal(1), kind: z.literal("stepStarted"), stepId: z.string().min(1) })
@@ -932,7 +979,7 @@ const runResultSchema = z
932
979
  .strict();
933
980
  export async function inspectAccepted(options) {
934
981
  try {
935
- const { inspectAcceptedAsync } = await import("@maxanstey-meridian/tandem-runtime");
982
+ const { inspectAcceptedAsync } = await import("./runtime/loader.mjs");
936
983
  return parseJson(acceptedValuesSchema, await inspectAcceptedAsync(options.ledgerPath, options.runId), "accepted values").map((value) => ({
937
984
  version: 1,
938
985
  kind: value.kind,
@@ -994,7 +1041,7 @@ export async function run(graph, initial, options = {}) {
994
1041
  return "";
995
1042
  })
996
1043
  : undefined;
997
- const { runRegisteredGraphAsync } = await import("@maxanstey-meridian/tandem-runtime");
1044
+ const { runRegisteredGraphAsync } = await import("./runtime/loader.mjs");
998
1045
  const resultJson = await runRegisteredGraphAsync(JSON.stringify({
999
1046
  contractVersion: 10,
1000
1047
  name: graph.name,
@@ -1002,6 +1049,7 @@ export async function run(graph, initial, options = {}) {
1002
1049
  initialState,
1003
1050
  persist: graph.persist,
1004
1051
  ledgerPath: options.ledgerPath,
1052
+ enableLedgerTools: options.enableLedgerTools ?? false,
1005
1053
  presentation: options.presentation,
1006
1054
  terminal: options.terminal,
1007
1055
  observationCallback,
@@ -1047,6 +1095,9 @@ function issues(schema, input) {
1047
1095
  catch {
1048
1096
  return JSON.stringify([{ path: "$", message: "Invalid JSON" }]);
1049
1097
  }
1098
+ return issuesParsed(schema, value);
1099
+ }
1100
+ function issuesParsed(schema, value) {
1050
1101
  try {
1051
1102
  parse(schema, value, "agent contract");
1052
1103
  return "";
@@ -1169,6 +1220,7 @@ function compileNode(node, stateSchema, callbacks) {
1169
1220
  return {
1170
1221
  ...base,
1171
1222
  kind: "parallel",
1223
+ ...(implementation.max !== undefined ? { max: implementation.max } : {}),
1172
1224
  branches: entries.map(([id, participant]) => ({
1173
1225
  id,
1174
1226
  participant: compileNode(participant, stateSchema, callbacks),
@@ -1203,18 +1255,7 @@ function compileWorkspace(id, configuration, stateSchema, callbacks) {
1203
1255
  name: z.string(),
1204
1256
  description: z.string(),
1205
1257
  command: z.string(),
1206
- arguments: z
1207
- .array(z
1208
- .object({
1209
- name: z.string(),
1210
- description: z.string(),
1211
- flag: z.string(),
1212
- pattern: z.string().optional(),
1213
- allowedValues: z.array(z.string()).optional(),
1214
- maxLength: z.number().optional(),
1215
- })
1216
- .strict())
1217
- .optional(),
1258
+ arguments: z.array(z.string()).optional(),
1218
1259
  })
1219
1260
  .strict()), value, `${id} workspace commands`);
1220
1261
  });
@@ -1275,15 +1316,29 @@ function compileWorkspace(id, configuration, stateSchema, callbacks) {
1275
1316
  return { pathCallback, commandsCallback, toolGroups, interceptCallback };
1276
1317
  }
1277
1318
  function compileAgentOutput(id, output, stateSchema, callbacks) {
1278
- const validate = callbacks.registerSync((_, input) => issues(output.schema, input));
1319
+ const raw = output.raw === true;
1320
+ const validate = raw
1321
+ ? callbacks.registerSync((_, input) => issuesParsed(z.unknown(), output.parse(JSON.parse(input))))
1322
+ : callbacks.registerSync((_, input) => issues(output.schema, input));
1279
1323
  const validateFor = output.validateFor
1280
- ? callbacks.registerSync((state, input) => validationProblems(output.validateFor(parseJson(stateSchema, state, `${id} state`), parseJson(output.schema, input, `${id} output`)), `${id} output contextual validation`))
1324
+ ? callbacks.registerSync((state, input) => validationProblems(output.validateFor(parseJson(stateSchema, state, `${id} state`), raw
1325
+ ? JSON.parse(input)
1326
+ : parseJson(output.schema, input, `${id} output`)), `${id} output contextual validation`))
1281
1327
  : undefined;
1282
- const apply = callbacks.registerSync((state, input) => serializeBoundary(stateSchema, output.apply(parseJson(stateSchema, state, `${id} state`), parseJson(output.schema, input, `${id} output`)), `${id} applied state`));
1328
+ const apply = callbacks.registerSync((state, input) => serializeBoundary(stateSchema, output.apply(parseJson(stateSchema, state, `${id} state`), raw
1329
+ ? JSON.parse(input)
1330
+ : parseJson(output.schema, input, `${id} output`)), `${id} applied state`));
1283
1331
  return {
1284
1332
  instructions: output.instructions,
1285
- jsonSchema: inputJsonSchema(output.schema, `${id} output schema`),
1286
- validateCallback: validate,
1333
+ ...(raw
1334
+ ? {
1335
+ raw: true,
1336
+ rawParseCallback: callbacks.registerSync((_, input) => JSON.stringify(output.parse(input))),
1337
+ }
1338
+ : {
1339
+ jsonSchema: inputJsonSchema(output.schema, `${id} output schema`),
1340
+ validateCallback: validate,
1341
+ }),
1287
1342
  validateForCallback: validateFor,
1288
1343
  applyCallback: apply,
1289
1344
  valueType: `${id}.output`,
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,26 @@
1
+ // Generated for: Tandem.NodeApiSpike.Bridge 0.1.0.0
2
+ // Generated by: Microsoft.JavaScript.NodeApi.Generator 0.9.0.0
3
+ /* eslint-disable */
4
+
5
+ const dotnet = require('node-api-dotnet/net10.0');
6
+ const path = require('node:path');
7
+ // @ts-ignore - https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/65252
8
+ const { dlopen, platform, arch } = require('node:process');
9
+
10
+ const moduleName = path.basename(__filename, __filename.match(/(\.[cm]?js)?$/)[0]);
11
+ module.exports = dotnet ? importDotnetModule(moduleName) : importAotModule(moduleName);
12
+
13
+ function importDotnetModule(moduleName) {
14
+ const moduleFilePath = path.join(__dirname, moduleName + '.dll');
15
+ return dotnet.require(moduleFilePath);
16
+ }
17
+
18
+ function importAotModule(moduleName) {
19
+ const ridPlatform = platform === 'win32' ? 'win' : platform === 'darwin' ? 'osx' : platform;
20
+ const ridArch = arch === 'ia32' ? 'x86' : arch;
21
+ const rid = `${ridPlatform}-${ridArch}`;
22
+ const moduleFilePath = path.join(__dirname, rid, moduleName + '.node');
23
+ const module = { exports: {} };
24
+ dlopen(module, moduleFilePath);
25
+ return module.exports;
26
+ }
@@ -0,0 +1,23 @@
1
+ // Generated for: Tandem.NodeApiSpike.Bridge 0.1.0.0
2
+ // Generated by: Microsoft.JavaScript.NodeApi.Generator 0.9.0.0
3
+ /* eslint-disable */
4
+
5
+ import './System.Runtime';
6
+
7
+
8
+ /** Adapts JavaScript-authored participants to the Tandem runtime. */
9
+ export namespace NodePipelineBridge {
10
+ /** Reads accepted semantic journal values from a packaged SQLite ledger. */
11
+ export function inspectAcceptedAsync(
12
+ ledgerPath: string,
13
+ runId: string,
14
+ ): Promise<string>;
15
+
16
+ /** Registers and runs a complete JavaScript-authored Tandem graph. */
17
+ export function runRegisteredGraphAsync(
18
+ definitionJson: string,
19
+ invokeSyncCallback: Func$4<string, string, string, string>,
20
+ invokeAsyncCallback: Func$5<string, string, string, AbortSignal, Promise<string>>,
21
+ cancellationToken?: AbortSignal,
22
+ ): Promise<string>;
23
+ }