Skip to content

Promptise Foundry 1.9.0

Choose a tag to compare

@cryxnet cryxnet released this 23 Oct 21:41
· 15 commits to main since this release

Runtime processes can pick their reasoning pattern. Traces keep the tenant and the session, record tool arguments as data and show refused calls and approval decisions. Plus fixes for promptise run --check with agent factories and a Prompt that reached the model twice.

Upgrade notes

  • A tool.call entry's metadata["arguments"] is JSON data, not text. It was the Python repr of the call ("{'sku': 'MS-30'}"); it is now a dict for a structured call ({"sku": "MS-30"}), with nested models as objects, and stays text only for a tool given plain text. Code that parsed the string should read the dict. Long strings are still cut at 2,000 characters, now per value. The OTLP span attribute promptise.arguments is now JSON text.
  • collector.purge_user("alice") and for_user("alice") no longer reach a tenant's alice. Without a tenant they match only entries recorded without one, as MemoryProvider.purge_user does. Pass tenant_id= or the isolation key ("acme::alice") for a tenant's user; purge_user logs a warning when it kept entries of a tenant's user with that id. The signatures are unchanged apart from the new keyword.
  • collector.get_users() lists isolation keys: "acme::alice" for a user with a tenant (it was "alice" for every tenant). Users without a tenant are listed as before.
  • AuditMiddleware(include_args=True) writes a nested Pydantic argument as a JSON object, not its str() ("sku='MS-30' qty=2"); dataclasses, dates and sets get their JSON form too. Existing log files still verify. StructuredLoggingMiddleware(include_args=True) does the same.
  • promptise run stats payloads have new keys: totals.tool_denied and a denied count per tool. Code that compared a tool row exactly needs updating.
  • A Prompt used as instructions now comes before other system messages -- before, it came after the first system message in the input (for example chat(system_prompt=...)). Check prompts that relied on the old order.
  • With a context engine, a Prompt's context providers run on every call -- before, only the build-time render was sent. Providers that are slow or have side effects now run once per call.

Added

  • ProcessConfig(agent_pattern=...) -- choose the reasoning pattern of a runtime process, so a run started by a cron schedule or a webhook can use "peoatr", "research" or any other name from AGENT_PATTERNS (or, in code, a PromptGraph). An unknown name fails when the config is created. .agent manifests set it with a top-level agent_pattern: key. Before, ProcessConfig refused the key and every process ran the default ReAct loop.
  • TimelineEntry.tenant_id and TimelineEntry.isolation_key -- every trace entry records the caller's tenant next to its user id. for_user() and purge_user() take tenant_id= (or the "tenant::user" key), query() takes tenant_ids=, and the OTLP transporter sets promptise.tenant_id.
  • Refused tool calls on the trace -- a call the autonomy budget refuses, or an approval gate denies, is a tool.call / tool.result with status="denied", denied_by and the reason. get_stats() counts them as tool_denied_count, and promptise run --devtools prints them and counts them in its summary.

Fixed

  • Two tenants' users with the same id merged in traces -- entries stored caller.user_id only, so acme's alice and globex's alice were one user, and purge_user("alice") deleted both.
  • chat(session_id=...) left the session empty in traces -- every entry of the run now carries it.
  • A call refused by the autonomy budget was missing from traces and --devtools -- with max_irreversible_per_run=3, the 4th call reached only the journal (tool_denied) and the permission_denied hook.
  • approval.* events reached the event notifier but not the timeline -- approval.requested, approval.granted and approval.denied are now recorded on the observed run (a CALLBACK transporter, --devtools), with a new approval.timeout entry, and a denied call's tool.result says status="denied" instead of looking like a successful call.
  • promptise run --check failed for an agent factory in a package -- with agent = "customer_agent.agent:create_agent", promptise run --mode chat --check reported "No module named 'customer_agent'" while the real run worked, because the check imported the factory before it put the project root on sys.path. --check now adds the project root and the python_path entries first, the same way the run does.
  • A Prompt as build_agent(instructions=...) reached the model twice -- its build-time render was the graph's system prompt, and the per-request render (with the context providers) was added as a second system message, so every block was sent twice on every call. The model now gets the per-request render once, as the start of its one system message, after a conversation flow's prompt and before the tool list. If the render fails or is empty, the build-time render is sent instead.
  • astream(), astream_with_tools() and the context-engine path skipped a Prompt's context providers -- they sent only the build-time render. They now send the per-request render too.
  • A PromptSuite as instructions sent <MySuite prompts=N> as a system message -- its build-time text was the suite's repr. It is now suite.system_prompt(), used for the cache key, the context engine's identity budget and the fallback.

Full changelog: https://docs.promptise.com/resources/changelog/