Skip to content

v1.4.0

Choose a tag to compare

@eloquentanalytics eloquentanalytics released this 03 Mar 06:35
· 3 commits to main since this release

DIAL 1.4.0

Migration Guide

ProposerContext.transitions changed from Record<string, string> to Record<string, TransitionDefinition>. If you have a custom strategyFn that reads transition targets, update every access:

// Before (1.3.x)
const toState = ctx.transitions[name];

// After (1.4.0)
const toState = ctx.transitions[name].target;

Machine definitions are not affected — the shorthand form { close: "closed" } still works everywhere. normalizeMachine converts it to { close: { target: "closed" } } internally.

New

  • TransitionDefinition type — transitions can now carry description and parameters alongside target. Import it: import type { TransitionDefinition } from "dialai". When a transition has description or parameters, DIAL automatically builds OpenAI-compatible tool definitions and uses native function calling.

    const machine = {
      machineName: "booking",
      initialState: "idle",
      goalState: "booked",
      states: {
        idle: {
          prompt: "Book a ride for the user",
          transitions: {
            book_ride: {
              target: "booked",
              description: "Book a ride to the destination",
              parameters: {
                type: "object",
                properties: {
                  destination: { type: "string" },
                  rideType: { type: "string", enum: ["standard", "premium"] },
                },
                required: ["destination"],
              },
            },
          },
        },
        booked: {},
      },
    };
  • callLlmWithTools(modelId, systemMessage, userMessage, tools, auditContext?) — new function that sends OpenAI-compatible tool definitions to an LLM endpoint. Returns a ToolCallResult with name, arguments, and reasoning. Throws NoToolCallError if the model responds with text instead of a tool call. callLlm is completely unchanged.

  • buildToolsFromTransitions(transitions) — converts Record<string, TransitionDefinition> into an array of OpenAI tool definitions. Returns null if no transitions have description or parameters (i.e., all are plain shorthand).

  • NoToolCallError — thrown by callLlmWithTools when the model returns text instead of a tool call. Has content (the text response) and usage fields.

  • parseModelId(raw) — parses modelId[tools=no] syntax. Returns { modelId, useTools }. Use [tools=no] suffix to skip the tool-calling attempt for models that don't support tools:

    await registerProposer({
      specialistId: "legacy-model",
      machineName: "booking",
      modelId: "some-model[tools=no]",
      strategyFnName: "firstAvailable",
    });
  • executeProposerLlm tool-calling path — when transitions have description/parameters and the model is not opted out via [tools=no], executeProposerLlm now tries callLlmWithTools first. If the model returns a tool call, the function name maps to transitionName and parsed arguments land in ProposerStrategyResult.metaJson. On NoToolCallError, it attempts to parse the text as DIAL JSON; if that fails, it falls back to the existing callLlm text path. HTTP errors re-throw without fallback.

Changes

  • ProposerContext.transitions is now Record<string, TransitionDefinition> (was Record<string, string>). Every custom strategyFn that reads ctx.transitions[name] must add .target. Search your codebase for ctx.transitions in any strategyFn callback.

  • ProposerStrategyResult.metaJson — tool call arguments are automatically placed here. If you already return metaJson from a custom strategy, no change needed. If you pass metaJson in submitProposal opts AND the strategy also returns metaJson, the opts value takes precedence.

  • submitProposal now merges metaJson from the strategy result into the proposal when the caller does not provide metaJson in opts.