Skip to content

v0.3.0

Choose a tag to compare

@shibayan shibayan released this 13 Aug 03:27
· 53 commits to master since this release
Immutable release. Only release title and notes can be modified.
6505ba0

The first minor since 0.2, and the first release after the public-API surface freeze was lifted:
six breaking changes settle the naming conventions and correct semantics against the reference
implementations, alongside Agent Skills, the Foundry Memory provider, the Invocations protocol,
and file-backed persistence for transcripts and skills.

  • [BREAKING] @polymind-inc/agent-framework-openai — the OpenAIChatClientOptions
    interface is renamed OpenAIChatClientConfigBase. It is the construction-time half of
    OpenAIChatClientConfig, and the package convention names construction types *Config and
    per-call types *Options (OpenAIChatOptions is unchanged); OpenAI was the one provider whose
    construction type broke that rule. OpenAIChatClientConfig itself — what new OpenAIChatClient(…)
    accepts — is unchanged, so only code that names the base interface directly is affected.
  • [BREAKING] the MCP acronym in public identifiers is now spelled Mcp, matching the official
    @modelcontextprotocol SDK and this framework's own newer API (McpConnection,
    mcpSkillsSource(), withMcpClientSpan). The wire format is unaffected. Renames —
    @polymind-inc/agent-framework-mcp: MCPClient → McpClient, MCPClientConfig →
    McpClientConfig; @polymind-inc/agent-framework-core: MCPToolOptions → McpToolOptions,
    SupportsMCPTool → SupportsMcpTool, supportsMCP → supportsMcp, and the capability method
    getMCPTool → getMcpTool (the OpenAI, Anthropic and Foundry clients implement the renamed
    method). There are no deprecated aliases; update imports and any custom ChatClient that
    declares the MCP capability.
  • [BREAKING] @polymind-inc/agent-framework-agentserver — resolveUnder and
    validatePathSegment are no longer exported from the package's main entry. They are path-safety
    primitives for file-backed stores, not part of the server protocol surface (the reference
    implementation exposes only the domain-scoped state-root helper, which stateRoot continues to
    mirror). The framework's own Foundry hosting adapter now reaches them — together with the shared
    atomic JSON file helpers readJsonFile / writeJsonFile, previously duplicated between the two
    packages — through the new ./internal subpath, an internal contract like
    @polymind-inc/agent-framework-openai/internal whose exports may change in any release.
  • [BREAKING] @polymind-inc/agent-framework-agentserver — HandlerContext gains two required
    fields: agentReference (the resolved agent this turn targets, always with a non-empty name)
    and agentSessionId (the resolved sandbox session id, as returned on x-agent-session-id).
    Handlers only read the context and are unaffected; code that constructs HandlerContext
    values — test doubles, custom protocol frontends — must now supply both.
  • [BREAKING] @polymind-inc/agent-framework-core — the function-calling loop no longer
    hardcodes OpenAI's conv_ prefix when deciding whether a conversation id advances between tool
    rounds. Which ids are stable service-side anchors is now the provider's declaration:
    ChatClientMetadata.stableConversationId, a new optional predicate the loop and the agent's
    session propagation consult. The built-in OpenAI, Azure OpenAI and Foundry clients declare it,
    so their behavior is unchanged. A custom ChatClient implementation that relied on the loop
    pinning conv_… ids must now declare the predicate on its metadata
    — without it, every
    conversation id a round reports advances the chain, matching the .NET and Python loops.
  • [BREAKING] @polymind-inc/agent-framework-foundry — FoundryChatClient no longer asks for
    reasoning.encrypted_content implicitly. Not every Foundry deployment supports encrypted
    reasoning, and one that does not rejects a request that asks for it — which the client did on
    every call without service-side storage, with no way to turn it off. A caller whose deployment
    does support encrypted reasoning, and who replays the transcript from their own side, must now
    list reasoning.encrypted_content in options.include
    ; without it a reasoning model's
    replayed transcript fails for missing reasoning content. Matches the upstream Python fix and the
    function-calling loop specification, which make the request an explicit caller opt-in on
    Foundry.
  • @polymind-inc/agent-framework-core — new Agent Skills support
    (#21): skillsProvider() is a
    ContextProvider that advertises each available skill's name and description in the system
    prompt and registers the three tools the model uses to pull one in on demand — load_skill,
    read_skill_resource and run_skill_script. Skills are declared in code with inlineSkill()
    (with skillResource() and skillScript(), the latter taking a Standard Schema it also
    validates against), or built from a SKILL.md document with markdownSkill();
    parseSkillMarkdown() exposes the frontmatter parser on its own. Sources come from
    inMemorySkillsSource() or any object implementing SkillsSource, and compose through
    aggregateSkills(), filterSkills(), deduplicateSkills() and cacheSkills(). Skills passed
    to the provider directly are cached and deduplicated for you; a source you supply is used exactly
    as given, because caching one that varies per agent or tenant would replay one run's skills for
    another. Every skill tool requires approval by default — approvals relaxes it per tool, and a
    toolApprovalMiddleware rule over the SKILL_TOOL_NAMES constant can reimpose it selectively
    on a relaxed tool (a middleware 'allow' cannot bypass a tool's own approval requirement). A skill or
    resource the model asks for and does not exist comes back as a message it can correct rather than
    a failed run; a skill a source cannot load is skipped and reported through onSkillError.
    Walking a directory of SKILL.md files is not part of the core, which has no filesystem;
    directorySkillsSource on the /node subpath covers it.
  • @polymind-inc/agent-framework-mcp — new mcpSkillsSource(), also reachable as
    McpClient.skillsSource(): discovers the Agent Skills an MCP server publishes by reading the
    well-known skill://index.json catalogue, fetching each SKILL.md body and any document it
    refers to only when the model asks. McpConnection.readResource() is exposed for it, with the
    same reconnect-once behaviour as callTool and a resources/read client span. A server with no
    catalogue contributes no skills; an index entry the framework cannot use — an archive skill, a
    malformed name — is skipped and named, while a server that refuses the request surfaces the
    failure rather than being read as an empty catalogue.
  • @polymind-inc/agent-framework-foundry — FoundryToolbox now serves the toolbox's Agent
    Skills as well as its tools: asSkillsProvider() returns a ready-made provider (and
    skillsSource() the source alone) over the connection the tools already use, so discovery
    carries the same per-call Entra token and x-agent-foundry-call-id, and a CONSENT_REQUIRED
    refusal arrives as the same typed ToolboxConsentRequiredError. The new loadTools: false
    option hides the toolbox's tools entirely — the gateway is never asked to list them — for an
    agent that wants only its skills.
  • @polymind-inc/agent-framework-foundry — new FoundryMemoryProvider: a ContextProvider
    backed by a Microsoft Foundry Memory Store
    (#25). It searches the store
    before each run — once per session for the user's profile memories, then per turn for memories
    relevant to the input — injects what it finds as a single user message under a configurable
    context prompt, and sends the completed turn back for extraction afterwards. A failed run is not
    stored. Memories are partitioned by a required scope, given as a value or as a function of
    the run and pinned to the session on first use, so one provider instance can serve every user of
    a hosted container; hostedUserScope() (exported from /hosting) resolves it from the platform
    user id of the turn. Service failures default to failureMode: 'continue' — the run proceeds
    without the memories — and 'throw' fails the run instead; onFailure observes both. The
    provider also carries the store operations a caller needs around it:
    ensureMemoryStoreCreated, getMemoryStore, deleteStoredMemories and whenUpdatesCompleted.
    The transport is fetch against the preview memory-store routes (Foundry-Features: MemoryStores=V1Preview) and is overridable, so tests need no live credentials.
  • @polymind-inc/agent-framework-agentserver — new InvocationsServer: the Foundry
    Invocations protocol (#29),
    served alongside the existing Responses protocol. The protocol prescribes no payload — the
    request body reaches the InvocationHandler unread, and the handler's Response is what the
    caller gets — while the server owns the routes (POST /invocations, GET /invocations/{id},
    POST /invocations/{id}/cancel, /readiness), invocation and session id resolution
    (x-agent-invocation-id; agent_session_id query → FOUNDRY_AGENT_SESSION_ID → generated),
    their echo on every response including errors, cancellation via InvocationContext.signal,
    opaque upstream-classified handler failures, SSE keep-alive injection for
    text/event-stream bodies, and W3C trace propagation with the
    azure.ai.agentserver.invocation_id / .session_id baggage. serve (on /agentserver/node)
    now accepts any { fetch, drain } protocol server — a widening, existing callers are
    unaffected.
  • @polymind-inc/agent-framework-foundry — new InvocationsHostServer (on /hosting):
    publishes an Agent over the Invocations protocol with the same wire contract as the Python
    adapter — request { "message": string, "stream"?: boolean }, plain-text responses, raw text
    chunks under text/event-stream when streaming. Conversations are held in process, partitioned
    per session id and — hosted — per platform user; callers continue a conversation by pinning the
    agent_session_id query parameter to the previous response's x-agent-session-id header.
    Hosted requests without the protocol-2.0.0 call id fail closed with 501, without a user id with
    400, as the Responses adapter does.
  • @polymind-inc/agent-framework-foundry — the hosting layer now exposes the turn's typed
    execution context to code running inside the agent
    (#23). getHostedAgentContext()
    (exported from /hosting) returns a frozen per-turn HostedAgentContext — the platform user id
    and call id, the correlation id, the response and conversation ids, the resolved agent
    reference, the sandbox session id, and the turn's AbortSignal — from any tool, context
    provider or middleware, and undefined outside a hosted turn. Concurrent turns on one container
    each see their own context; the stores that persist per-user state keep taking their partition
    key as an explicit argument. There is deliberately no per-request tenant field: the platform's
    trust boundary injects only the user id and call id, and a hosted container is deployed per
    agent inside one tenant.
  • @polymind-inc/agent-framework-openai — new includeReasoningEncryptedContent construction
    option (default true, so OpenAI and Azure OpenAI are unchanged). Setting it to false
    suppresses the implicit reasoning.encrypted_content request for an endpoint that rejects it;
    an entry the caller lists in include themselves is always sent either way. Mirrors the .NET
    clients' option of the same name.
  • @polymind-inc/agent-framework-core — a history provider can opt into storing the
    messages other context providers injected into a run: HistoryStoreOptions.storeContextMessages
    takes true for all of them, or a list of sourceIds for just those providers. The default
    stays as before — the run's input and the response — matching the reference implementations'
    default; the opt-in is the knob they offer that was missing here.
  • @polymind-inc/agent-framework-core — new FileHistoryProvider on the /node subpath:
    keeps the transcript in a JSON Lines file per session, using the same layout as the Python
    file-backed provider so the files interoperate, and a session survives a process restart without
    a custom provider.
  • @polymind-inc/agent-framework-core — new directorySkillsSource on the /node
    subpath: walks a directory of SKILL.md skill folders — the convention all three reference
    implementations support — and serves them as a SkillsSource for skillsProvider().
  • @polymind-inc/agent-framework-mcp — McpClient accepts a header provider
    (McpHeaderProvider, sync or async) in place of a static headers record. It is re-evaluated
    per request, so a credential that refreshes can be expressed without a custom fetch wrapper,
    and the headers are scoped to the server's origin so a redirect elsewhere cannot carry them
    along.
  • @polymind-inc/agent-framework-core — the ENABLE_SENSITIVE_DATA compatibility alias
    accepts the same spellings as the Python reader: on now enables message-content capture —
    previously it silently read as unset, the exact cross-language case the alias exists for — and
    off is an explicit negative rather than falling through to the OTel-named variables.
  • @polymind-inc/agent-framework-openai — the Responses wire mappings the Foundry hosting
    adapter replays (the mcp_call / search / code-interpreter items, MCP output stringification,
    and the encrypted-reasoning lookup) are shared through an undocumented ./internal entry
    instead of hand-maintained mirrors, so the replay path and the live provider path cannot drift;
    the call-id fallback order now matches the Python reference on both.
  • @polymind-inc/agent-framework-core — what happens when a caller stops consuming a run
    early (break, an aborted signal) and how token usage is read after draining a stream are now
    documented contracts on AgentRunStream / ResponseStream, each pinned by tests.
  • Repository: the Baseline v0.1 public-API surface freeze is lifted — surface changes now require
    grounding in the reference implementations, and the gate on new feature areas stays. Large
    internal modules were split into focused ones and duplicated internal logic consolidated, with
    reduced streaming hot-path overhead and no behavior change; CI actions and dependencies were
    bumped.