@elevasis/sdk 1.42.0 → 1.44.0

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.
@@ -237,113 +237,6 @@ interface IExecutionLogger {
237
237
  error(message: string, context?: LogContext): void;
238
238
  }
239
239
 
240
- /**
241
- * Model Configuration
242
- * Centralized model information, configuration, options, constraints, and validation
243
- * Single source of truth for all model-related definitions
244
- * Update manually when pricing changes or new models are added
245
- */
246
-
247
- /**
248
- * Supported Open AI models (direct SDK access)
249
- */
250
- type OpenAIModel = 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5.4-nano';
251
- /**
252
- * Supported OpenRouter models (explicit union for type safety)
253
- */
254
- type OpenRouterModel = 'openrouter/z-ai/glm-5';
255
- /**
256
- * Supported Google models (direct SDK access)
257
- */
258
- type GoogleModel = 'gemini-3-flash-preview' | 'gemini-3.1-flash-lite-preview';
259
- /**
260
- * Supported Anthropic models (direct SDK access via @anthropic-ai/sdk)
261
- */
262
- type AnthropicModel = 'claude-opus-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001' | 'claude-haiku-4-5';
263
- /** Supported LLM models */
264
- type LLMModel = OpenAIModel | OpenRouterModel | GoogleModel | AnthropicModel | 'mock';
265
- /**
266
- * GPT-5 model options schema
267
- */
268
- declare const GPT5OptionsSchema: z.ZodObject<{
269
- reasoning_effort: z.ZodOptional<z.ZodEnum<{
270
- minimal: "minimal";
271
- low: "low";
272
- medium: "medium";
273
- high: "high";
274
- }>>;
275
- verbosity: z.ZodOptional<z.ZodEnum<{
276
- low: "low";
277
- medium: "medium";
278
- high: "high";
279
- }>>;
280
- }, z.core.$strip>;
281
- /**
282
- * OpenRouter model options schema
283
- * OpenRouter-specific options for routing and transforms
284
- */
285
- declare const OpenRouterOptionsSchema: z.ZodObject<{
286
- transforms: z.ZodOptional<z.ZodArray<z.ZodString>>;
287
- route: z.ZodOptional<z.ZodEnum<{
288
- fallback: "fallback";
289
- }>>;
290
- }, z.core.$strip>;
291
- /**
292
- * Google model options schema
293
- * Gemini 3 specific options for thinking depth control
294
- */
295
- declare const GoogleOptionsSchema: z.ZodObject<{
296
- thinkingLevel: z.ZodOptional<z.ZodEnum<{
297
- minimal: "minimal";
298
- low: "low";
299
- medium: "medium";
300
- high: "high";
301
- }>>;
302
- }, z.core.$strip>;
303
- /**
304
- * Anthropic model options schema
305
- * Currently empty - future options must be added per supported model family
306
- */
307
- declare const AnthropicOptionsSchema: z.ZodObject<{}, z.core.$strict>;
308
- /**
309
- * Infer TypeScript types from schemas
310
- */
311
- type GPT5Options = z.infer<typeof GPT5OptionsSchema>;
312
- type MockOptions = Record<string, never>;
313
- type OpenRouterOptions = z.infer<typeof OpenRouterOptionsSchema>;
314
- type GoogleOptions = z.infer<typeof GoogleOptionsSchema>;
315
- type AnthropicOptions = z.infer<typeof AnthropicOptionsSchema>;
316
- type ModelSpecificOptions = GPT5Options | MockOptions | OpenRouterOptions | GoogleOptions | AnthropicOptions;
317
- /**
318
- * Model configuration for LLM execution
319
- * Belongs in resource definition (AgentDefinition, WorkflowDefinition, etc.)
320
- */
321
- interface ModelConfig {
322
- model: LLMModel;
323
- provider: 'openai' | 'anthropic' | 'openrouter' | 'google' | 'mock';
324
- apiKey: string;
325
- temperature?: number;
326
- /** Maximum output tokens per LLM call. NOT the model's context window — see ModelInfo.maxTokens for that. */
327
- maxOutputTokens?: number;
328
- topP?: number;
329
- /**
330
- * Model-specific options (flat structure)
331
- * Options are model-specific, not vendor-specific
332
- * Available options defined in MODEL_INFO per model
333
- * Validated at build time via validateModelOptions()
334
- */
335
- modelOptions?: ModelSpecificOptions;
336
- }
337
-
338
- /**
339
- * What happened to `strict` on a request, recorded per call rather than inferred.
340
- *
341
- * `applied` and `notAttempted` are the two states that a refusal-only field cannot tell apart —
342
- * both leave `strictRefusalReasons` empty. Recording the verdict positively is what makes "was
343
- * this agent's output actually enforced?" answerable from an `ai_calls` row.
344
- */
345
- type StrictStatus = 'applied' | 'refused' | 'compileRejected' | 'notAttempted';
346
-
347
240
  declare const ResourceGovernanceStatusSchema: z.ZodEnum<{
348
241
  active: "active";
349
242
  deprecated: "deprecated";
@@ -706,165 +599,194 @@ type AgentResourceEntry = z.infer<typeof AgentResourceEntrySchema>;
706
599
  type ResourceEntry = z.infer<typeof ResourceEntrySchema>;
707
600
 
708
601
  /**
709
- * Shared form field types for dynamic form generation
710
- * Used by: Command Queue, Execution Runner UI, future form-based features
602
+ * Memory type definitions
603
+ * Types for agent memory management with semantic entry types
711
604
  */
712
605
  /**
713
- * Supported form field types for action payloads
714
- * Maps to Mantine form components
606
+ * Semantic memory entry types
607
+ * Use-case agnostic types that describe the purpose of each entry
608
+ * Memory types mirror action types for clarity and filtering
715
609
  */
716
- type FormFieldType = 'text' | 'textarea' | 'number' | 'select' | 'checkbox' | 'radio' | 'richtext';
610
+ type MemoryEntryType = 'context' | 'input' | 'reasoning' | 'tool-result' | 'error';
717
611
  /**
718
- * Form field definition
612
+ * Who authored an entry's content.
613
+ *
614
+ * This is what lets the assembled prompt tell framework-authored text apart from text that
615
+ * originated outside the trust boundary. `'framework'` content is ours; the other three are not
616
+ * and are rendered inside the JSON data envelope (see `MemoryManager.toContextParts`).
719
617
  */
720
- interface FormField {
721
- /** Field key in payload object */
722
- name: string;
723
- /** Field label for UI */
724
- label: string;
725
- /** Field type (determines UI component) */
726
- type: FormFieldType;
727
- /** Default value */
728
- defaultValue?: unknown;
729
- /** Required field */
730
- required?: boolean;
731
- /** Placeholder text */
732
- placeholder?: string;
733
- /** Help text */
734
- description?: string;
735
- /** Options for select/radio */
736
- options?: Array<{
737
- label: string;
738
- value: string | number;
739
- }>;
740
- /** Min/max for number */
741
- min?: number;
742
- max?: number;
743
- /** Path to context value for pre-filling (dot notation, e.g., 'proposal.summary') */
744
- defaultValueFromContext?: string;
745
- }
618
+ type MemoryEntrySource = 'framework' | 'user' | 'tool' | 'model';
746
619
  /**
747
- * Form schema for action payload collection
620
+ * Memory entry - represents a single entry in agent memory
621
+ * Stored in agent memory, translated by adapters to vendor-specific formats
748
622
  */
749
- interface FormSchema {
750
- /** Form title */
751
- title?: string;
752
- /** Form description */
753
- description?: string;
754
- /** Form fields */
755
- fields: FormField[];
623
+ interface MemoryEntry {
624
+ type: MemoryEntryType;
625
+ content: string;
626
+ timestamp: number;
627
+ turnNumber: number | null;
628
+ iterationNumber: number | null;
629
+ /**
630
+ * Provenance. **Optional on purpose** — `undefined` means unknown, which is what every
631
+ * pre-existing snapshot and every not-yet-redeployed tenant bundle produces. Read sites MUST
632
+ * test `== null`, never `=== undefined`: the `inTurnScope` predicate in `manager.ts` is the
633
+ * cautionary precedent, where a `=== undefined` check silently dropped every `null`-stamped
634
+ * entry. `isMemoryEntry` is deliberately NOT tightened to require this field; doing so would
635
+ * make every stored snapshot fail validation, and `restoreSessionMemory` fails open by
636
+ * starting the agent with empty memory rather than throwing.
637
+ */
638
+ source?: MemoryEntrySource;
639
+ /**
640
+ * Which tool produced this entry. Set on `tool-result` entries so the model can tell N parallel
641
+ * results apart -- the framework instructs batching independent tool calls in one iteration, and
642
+ * an anonymous result is unattributable the moment two land in the same iteration. `addToolError`
643
+ * already carries this (folded into its `content` JSON); this is the same fact for the success
644
+ * path, carried as a real field instead of prose the caller has to parse back out.
645
+ */
646
+ toolName?: string;
647
+ /**
648
+ * Present when `truncateContent` cut this entry's `content` to fit its token budget. A sibling
649
+ * field, never text appended into `content` -- the notice used to be spliced into the string
650
+ * itself, which could (and did) land inside a JSON string literal `truncateContent` had just cut
651
+ * open, breaking `JSON.parse` on the far end. Absent means never truncated.
652
+ */
653
+ truncated?: {
654
+ omittedTokens: number;
655
+ };
656
+ /**
657
+ * Prompt-injection warning types found in `content`, screened once here -- when the entry is
658
+ * written -- instead of by re-scanning the whole accumulated envelope on every iteration it gets
659
+ * re-sent for (`screenRequest`'s `data-envelope` slot used to do exactly that). Empty array means
660
+ * screened and clean; `undefined` means never screened (entries that bypass `addToHistory`/`set`,
661
+ * or pre-existing snapshots from before this field existed).
662
+ */
663
+ warnings?: string[];
756
664
  }
757
-
758
665
  /**
759
- * Execution interface configuration
760
- * Defines how a resource is executed via the UI (forms, scheduling, webhooks)
761
- * Applies to both agents and workflows
666
+ * Agent memory - Self-orchestrated memory with session + working storage
667
+ * Agent has full control over what persists, framework handles auto-compaction
762
668
  */
763
- interface ExecutionInterface {
764
- /** Form configuration for execution inputs */
765
- form: ExecutionFormSchema;
766
- /** Optional: Schedule configuration */
767
- schedule?: ScheduleConfig;
768
- /** Optional: Webhook trigger configuration */
769
- webhook?: WebhookConfig;
669
+ interface AgentMemory {
670
+ /**
671
+ * Session memory - Persists for session/conversation duration
672
+ * Never auto-trimmed by framework
673
+ * Agent-managed key-value store for critical information
674
+ * Agent provides strings, framework wraps in MemoryEntry
675
+ */
676
+ sessionMemory: Record<string, MemoryEntry>;
677
+ /**
678
+ * Working memory - Execution history
679
+ * Automatically compacted by framework when needed
680
+ * Agent doesn't control compaction
681
+ */
682
+ history: MemoryEntry[];
770
683
  }
771
684
  /**
772
- * Execution form schema
773
- * Extends FormSchema with execution-specific fields
685
+ * Memory status for agent awareness
774
686
  */
775
- interface ExecutionFormSchema extends FormSchema {
687
+ interface MemoryStatus {
688
+ sessionMemoryKeys: number;
689
+ sessionMemoryLimit: number;
690
+ sessionMemoryTokens: number;
691
+ sessionMemoryTokenLimit: number;
776
692
  /**
777
- * Field mappings to resource input schema
778
- * Maps form field names to contract input paths
779
- * If omitted, field names must match contract input keys exactly
693
+ * History tokens as a percentage of `historyBudget` — history ALONE, not history plus session
694
+ * memory. It previously reported the combined total under this name, so session memory growth
695
+ * read as history pressure and triggered history compaction that could not relieve it.
780
696
  */
781
- fieldMappings?: Record<string, string>;
697
+ historyPercent: number;
782
698
  /**
783
- * Submit button configuration
784
- * Default: { label: 'Run', loadingLabel: 'Running...' }
699
+ * Tokens the history entries **in scope for the requested turn** occupy — the same set
700
+ * `toContextParts` puts in the envelope. Equal to `storedHistoryTokens` when `getStatus` is
701
+ * called without a turn.
702
+ *
703
+ * This is the number the model is shown, and it is scoped because the model is handed a scoped
704
+ * set. Counting the whole cross-turn array here meant the framing quoted the size of a store
705
+ * while the envelope beside it carried one turn's worth of it.
785
706
  */
786
- submitButton?: {
787
- label?: string;
788
- loadingLabel?: string;
789
- confirmMessage?: string;
790
- };
707
+ historyTokens: number;
708
+ /**
709
+ * Tokens the **entire** history array occupies, across every turn the session snapshot restored.
710
+ *
711
+ * This is what compaction measures, because compaction trims that array. Scoping it to a turn
712
+ * would let the store grow without bound whenever the current turn happened to be small.
713
+ */
714
+ storedHistoryTokens: number;
715
+ /** `storedHistoryTokens` as a percentage of `historyBudget`. The auto-compaction trigger. */
716
+ storedHistoryPercent: number;
717
+ historyBudget: number;
791
718
  }
792
719
  /**
793
- * Schedule configuration for automated execution
720
+ * Memory constraints (optional limits)
794
721
  */
795
- interface ScheduleConfig {
796
- /** Whether scheduling is enabled for this resource */
797
- enabled: boolean;
798
- /** Default schedule (cron expression) */
799
- defaultSchedule?: string;
800
- /** Allowed schedule patterns (if restricted) */
801
- allowedPatterns?: string[];
722
+ interface MemoryConstraints {
723
+ maxSessionMemoryKeys?: number;
724
+ maxMemoryTokens?: number;
802
725
  }
726
+
803
727
  /**
804
- * Webhook configuration for external triggers
728
+ * Types for the schema compiler. `compile.ts` walks a `JsonSchema` once, driven entirely by a
729
+ * `ProviderDialect`, and every server adapter compiles through it.
805
730
  */
806
- interface WebhookConfig {
807
- /** Whether webhook trigger is enabled */
808
- enabled: boolean;
809
- /** Expected payload schema (for documentation) */
810
- payloadSchema?: unknown;
811
- }
812
-
813
- interface WorkflowConfig extends ResourceDefinition {
814
- type: 'workflow';
815
- /** OM descriptor backing canonical identity and governance metadata. */
816
- resource?: WorkflowResourceEntry;
817
- }
818
- interface WorkflowStepDefinition {
819
- id: string;
820
- name: string;
821
- description: string;
822
- }
823
- type StepHandler = (input: unknown, context: ExecutionContext) => Promise<unknown>;
824
- interface LinearNext {
825
- type: 'linear';
826
- target: string;
827
- }
828
- interface ConditionalNext {
829
- type: 'conditional';
830
- routes: Array<{
831
- condition: (data: unknown) => boolean;
832
- target: string;
833
- }>;
834
- default: string;
835
- }
836
- type NextConfig = LinearNext | ConditionalNext | null;
837
- interface WorkflowStep extends WorkflowStepDefinition {
838
- handler: StepHandler;
839
- inputSchema: z.ZodSchema;
840
- outputSchema: z.ZodSchema;
841
- next: NextConfig;
842
- }
843
- interface WorkflowDefinition {
844
- config: WorkflowConfig;
845
- contract: Contract;
846
- steps: Record<string, WorkflowStep>;
847
- entryPoint: string;
731
+ /**
732
+ * What happened to `strict` on a request, recorded per call rather than inferred.
733
+ *
734
+ * `applied` and `notAttempted` are the two states that a refusal-only field cannot tell apart --
735
+ * both leave `strictRefusalReasons` empty. Recording the verdict positively is what makes "was
736
+ * this agent's output actually enforced?" answerable from an `ai_calls` row.
737
+ */
738
+ type StrictStatus = 'applied' | 'refused' | 'compileRejected' | 'notAttempted';
739
+ /**
740
+ * A JSON Schema node, typed enough to be useful without pretending to validate the spec.
741
+ *
742
+ * The compiler has to accept schemas that arrive OUTSIDE the strict subset (that is the whole
743
+ * point of a dialect that can refuse or rewrite them) as well as the `$ref`/`$defs`/`const`/
744
+ * `$schema` shapes the strict subset has no vocabulary for at all. The index signature exists
745
+ * because tenant schemas carry keywords (`minLength`, `pattern`, `minimum`, ...) this compiler
746
+ * drops or refuses on, and they still need somewhere to type-check while they pass through
747
+ * `Object.entries`.
748
+ */
749
+ interface JsonSchema {
750
+ type?: string | string[];
848
751
  /**
849
- * Metrics configuration for ROI calculations
850
- * Optional: Only needed if tracking automation savings
752
+ * The value is `JsonSchema | undefined`, not `JsonSchema`, because a property really can be
753
+ * declared with nothing describing it. `buildIterationResponseSchema` emits one per tool as
754
+ * `input: tool.inputSchema`, and `ToolDefinition.inputSchema` is typed `unknown` -- a tool
755
+ * deployed without one puts `undefined` under a key that exists.
756
+ *
757
+ * Both readers already handle it: `compileSchema` passes each value through `convertNode`, which
758
+ * takes `unknown`, and `collectErrors` opens with `if (!schema || typeof schema !== 'object')`
759
+ * above a comment naming this exact case. Declaring the value non-optional only hid that they
760
+ * were right to.
851
761
  */
852
- metricsConfig?: ResourceMetricsConfig;
762
+ properties?: Record<string, JsonSchema | undefined>;
763
+ items?: JsonSchema;
764
+ anyOf?: JsonSchema[];
765
+ oneOf?: JsonSchema[];
766
+ allOf?: JsonSchema[];
767
+ required?: string[];
768
+ additionalProperties?: boolean | JsonSchema;
769
+ minItems?: number;
770
+ maxItems?: number;
771
+ format?: string;
772
+ enum?: unknown[];
773
+ const?: unknown;
774
+ description?: string;
775
+ default?: unknown;
776
+ $ref?: string;
777
+ $defs?: Record<string, JsonSchema>;
778
+ definitions?: Record<string, JsonSchema>;
779
+ $schema?: string;
780
+ $id?: string;
781
+ $anchor?: string;
853
782
  /**
854
- * Execution interface configuration (optional)
855
- * If provided, workflow appears in Execution Runner UI
783
+ * OpenAPI's nullability spelling, which is not JSON Schema's. It is declared because
784
+ * `response-schema-validator.ts` READS it (`schemaPermitsNull`) -- Google's schema dialect is
785
+ * OpenAPI-derived, so a schema that reaches the validator can carry it. No dialect in `compile.ts`
786
+ * writes or rewrites it; the canonical spelling this compiler emits is `type: ['x', 'null']`.
856
787
  */
857
- interface?: ExecutionInterface;
858
- /**
859
- * Lead-gen processing stage this workflow implements (optional).
860
- * Must match a key in the platform lead-gen stage catalog.
861
- * Used by org-os graph derivation to surface workflow→stage edges and
862
- * by pipeline_config validation to confirm each catalog stage has an
863
- * implementing workflow before a list is activated.
864
- *
865
- * Example: stageImplemented: 'verified' on the email-verification workflow.
866
- */
867
- stageImplemented?: string;
788
+ nullable?: boolean;
789
+ [key: string]: unknown;
868
790
  }
869
791
 
870
792
  /**
@@ -879,6 +801,31 @@ interface WorkflowDefinition {
879
801
  interface LLMMessage {
880
802
  role: 'system' | 'user' | 'assistant';
881
803
  content: string;
804
+ /**
805
+ * Marks this message as the end of a byte-stable prefix worth an Anthropic cache breakpoint,
806
+ * beyond the one the system prompt already gets. Anthropic's rule is "everything up to and
807
+ * including the marked block is cached", so this only ever needs to sit on ONE message -- the
808
+ * last one before content that changes.
809
+ *
810
+ * `buildAgentMessages` sets it on the last replayed prior-turn message: conversation history is
811
+ * fixed for the whole turn (only the framing/envelope after it grow per iteration), so it is the
812
+ * only part of a session agent's messages, besides the system prompt, that is ever byte-identical
813
+ * call to call. A hint rather than a mechanism deliberately -- an adapter that does not read it
814
+ * (OpenAI, OpenRouter, any test stub) just ignores the extra property; only the Anthropic adapter
815
+ * turns it into a wire `cache_control` block.
816
+ */
817
+ cacheBreakpoint?: boolean;
818
+ /**
819
+ * Prompt-injection warning types already found in this message's content, when the caller has
820
+ * already screened it and wants `screenRequest` to use that verdict instead of re-scanning.
821
+ *
822
+ * Set only on the data-envelope message by `buildAgentMessages`, sourced from
823
+ * `MemoryContextParts.envelopeWarnings` -- itself an aggregate of `MemoryEntry.warnings` stamped
824
+ * once per fragment when it entered memory. `undefined` means "not pre-screened"; `screenRequest`
825
+ * falls back to scanning the content directly, which is what every other message role/slot still
826
+ * does and what a hand-built message (tests, other callers) gets by default.
827
+ */
828
+ envelopeWarnings?: string[];
882
829
  }
883
830
  /**
884
831
  * Generic LLM generation request
@@ -886,16 +833,86 @@ interface LLMMessage {
886
833
  */
887
834
  interface LLMGenerateRequest {
888
835
  messages: LLMMessage[];
889
- responseSchema: unknown;
836
+ /**
837
+ * JSON Schema for structured output. Omit it for an unstructured call.
838
+ *
839
+ * Absence is what turns validation off: `runGeneratePipeline` skips `validateResponseSchema`
840
+ * entirely when this is missing, whatever `validationSchema` holds.
841
+ *
842
+ * This was declared `responseSchema: unknown` -- required, and typed as nothing. `unknown` admits
843
+ * `undefined`, so "required" only ever forced the KEY to be written, and `createLLMCallTool`
844
+ * writes it as `undefined` on every call where the model supplies no usable schema. There was no
845
+ * type error available for that, and three separate layers re-derived the same nullability at
846
+ * runtime under three different rules -- truthiness in the pipeline, an object check in the
847
+ * validator, and a `'type'`-key check in the tool. Because the pipeline's was truthiness, `null`,
848
+ * `0` and `''` all quietly meant "no structured output" while the type insisted a schema was
849
+ * mandatory. Optional-and-typed is what those three were compensating for.
850
+ */
851
+ responseSchema?: JsonSchema;
890
852
  /** Maximum output tokens per LLM call. NOT the model's context window — see ModelInfo.maxTokens for that. */
891
853
  maxOutputTokens?: number;
892
854
  temperature?: number;
893
855
  topP?: number;
894
856
  signal?: AbortSignal;
857
+ /**
858
+ * Caller-supplied acceptance step (Wave D2b / decision A15). A pipeline-aware adapter
859
+ * (`UniversalLLMAdapter`, via `runGeneratePipeline`) runs this once per retry attempt, right
860
+ * after the response has passed `responseSchema` validation. Throw to reject the attempt --
861
+ * rejection is classified exactly like a thrown `LLMResponseParseError` from
862
+ * `validateResponseSchema`: retryable, no circuit-breaker verdict, and the attempt is recorded as
863
+ * a failure (`ai_calls` validation-failure row) rather than a clean success. Returning normally
864
+ * (including `undefined`) accepts the response.
865
+ *
866
+ * Optional, and a HINT rather than a dependency -- an adapter that does not read this field
867
+ * simply ignores it, so a caller must not assume it ran:
868
+ * - A bare test-stub `LLMAdapter` (many exist in this codebase) does not invoke it.
869
+ * - `PostMessageLLMAdapter` (`packages/sdk/src/worker/llm-adapter.ts`) cannot forward it at all --
870
+ * functions cannot be structured-cloned across the worker `postMessage` boundary, so its
871
+ * `params` object is built from an explicit allowlist that omits `accept`. The field is dropped
872
+ * before `postMessage` is ever called (no `DataCloneError`), and the parent-side handler that
873
+ * fulfils the call (`tool-dispatcher.ts`'s `case 'llm'`) rebuilds its own `LLMGenerateRequest`
874
+ * from that allowlisted payload, so there is nothing to forward even in principle. This is the
875
+ * path every deployed org-bundle agent and the `command-center-assistant` static module run
876
+ * through today -- `accept` does not reach their retry loop.
877
+ *
878
+ * This is not a validation mechanism on its own: it does not decide whether output is acceptable,
879
+ * the caller's function does, by throwing or not. `callLLMForAgentIteration`
880
+ * (`execution/engine/agent/reasoning/adapters/agent-adapter-helpers.ts`) passes its Zod parse of
881
+ * the iteration response as this field, so a malformed-but-schema-valid iteration is re-sampled
882
+ * inside the retry loop instead of losing the turn -- for the in-process callers that can see it.
883
+ */
884
+ accept?: (output: unknown) => void;
885
+ /**
886
+ * The schema the RESPONSE is validated against, when that must differ from the schema the
887
+ * provider was asked to sample against. Defaults to `responseSchema` when omitted.
888
+ *
889
+ * **This does not affect what is sent to the provider.** `responseSchema` remains the only schema
890
+ * an adapter puts on the wire; this one is read solely by `runGeneratePipeline`'s validation step.
891
+ * Whether validation happens at all is still decided by `responseSchema` -- a request with no
892
+ * `responseSchema` is unstructured and stays unvalidated, whatever this field holds.
893
+ *
894
+ * A caller may legitimately ACCEPT A SUPERSET of what it ASKS FOR -- a document that validates a
895
+ * response more leniently than the one the provider was asked to sample against. No caller in this
896
+ * codebase supplies one today (agent iterations validate with a single Zod parse instead, see
897
+ * `agent-adapter-helpers.ts`), but the mechanism stays: `validateResponseSchema` does not descend
898
+ * into `anyOf`/`oneOf` regardless of which document is supplied here, so this field only ever
899
+ * changes which top-level/required/type keywords are checked, never which acceptance contract a
900
+ * union is read as.
901
+ *
902
+ * Unlike `accept` above, this is DATA. It is structured-cloneable, so it survives the worker
903
+ * `postMessage` boundary that drops `accept`: `PostMessageLLMAdapter` forwards it in its params
904
+ * allowlist and `tool-dispatcher.ts`'s `case 'llm'` puts it back on the `LLMGenerateRequest` it
905
+ * rebuilds parent-side. That is why a divergence expressible as a schema belongs here rather than
906
+ * in a callback -- deployed org-bundle agents run on the far side of that boundary.
907
+ */
908
+ validationSchema?: JsonSchema;
895
909
  }
896
910
  /**
897
911
  * Generic LLM generation response
898
- * Usage field is internal-only (stripped by UniversalLLMAdapter wrapper)
912
+ * `usage`, `cost`, `strictStatus` and `strictRefusalReasons` are observability fields. They are
913
+ * **read** by `UniversalLLMAdapter` and lifted onto the `ai_calls` row; they are **not removed**.
914
+ * The wrapper returns the base adapter's response object as-is, so a caller can observe all four.
915
+ * Earlier revisions of this file claimed they were stripped — they never were.
899
916
  */
900
917
  interface LLMGenerateResponse<T = unknown> {
901
918
  output: T;
@@ -903,35 +920,53 @@ interface LLMGenerateResponse<T = unknown> {
903
920
  inputTokens: number;
904
921
  outputTokens: number;
905
922
  totalTokens: number;
923
+ /**
924
+ * Anthropic-only: input tokens served from the prompt cache (`cache_read_input_tokens`), billed
925
+ * at 0.1x the base input rate. Optional so OpenAI/OpenRouter usage objects, which never report
926
+ * this, stay valid -- absent means "this provider doesn't report it," not "zero were read."
927
+ */
928
+ cacheReadInputTokens?: number;
929
+ /**
930
+ * Anthropic-only: input tokens written to the prompt cache this call
931
+ * (`cache_creation_input_tokens`), billed at 1.25x the base input rate. Same optionality
932
+ * rationale as `cacheReadInputTokens`.
933
+ */
934
+ cacheCreationInputTokens?: number;
906
935
  };
907
936
  cost?: number;
908
937
  /**
909
- * What actually happened to `strict` on the request that produced this response. Every server
910
- * adapter sets it on every call, so the value is a statement rather than an inference:
938
+ * What actually happened to `strict` on the request that produced this response.
911
939
  *
912
940
  * - `applied` — the request carried `strict: true` and the grammar was in effect
913
- * - `refused` — `toStrictSchema` could not express the schema, so the request went out unstrict
914
- * - `compileRejected` — the schema passed `toStrictSchema` but the provider's grammar compiler
941
+ * - `refused` — `compileSchema` could not express the schema, so the request went out unstrict
942
+ * - `compileRejected` — the schema passed `compileSchema` but the provider's grammar compiler
915
943
  * rejected it at request time, and the call was retried unstrict
916
- * - `notAttempted` — this adapter does not send strict at all (OpenAI, Google, OpenRouter)
944
+ * - `notAttempted` — the adapter did not send `strict` on this call
917
945
  *
918
946
  * This exists because `strictRefusalReasons` alone cannot answer the question. Its absence means
919
947
  * "strict held" OR "nothing ever tried", and a prod run that recorded zero refusals while
920
948
  * returning an array-typed field as a string is exactly the case where the difference matters.
921
949
  *
922
- * Internal-only, like `usage` `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
923
- * strips it before the response reaches callers.
950
+ * **Do not read this as "provider X never sends strict."** It describes one call, not an adapter.
951
+ * A previous revision of this comment enumerated OpenAI, Google and OpenRouter as adapters that
952
+ * never send `strict`, which was false for OpenRouter — it sends `strict: true` whenever the
953
+ * schema compiles, and separately reports `notAttempted`. That producer bug is still live; the
954
+ * fix is to make the value a return of schema compilation rather than a per-adapter literal.
955
+ * `MockAdapter` sets no value at all, so absence does not imply `notAttempted` either.
956
+ *
957
+ * Observability only — `UniversalLLMAdapter` lifts it onto the `ai_calls` row. It is not removed
958
+ * from the response.
924
959
  */
925
960
  strictStatus?: StrictStatus;
926
961
  /**
927
962
  * Why this call went out WITHOUT `strict`, on an adapter that tried to send it with one.
928
963
  *
929
964
  * The detail behind a `refused` / `compileRejected` `strictStatus` — the short, stable reason
930
- * strings `toStrictSchema` computes. Read `strictStatus` to answer "was it enforced"; read this
965
+ * strings `compileSchema` computes. Read `strictStatus` to answer "was it enforced"; read this
931
966
  * to answer "why not".
932
967
  *
933
- * Internal-only, like `usage` — `UniversalLLMAdapter` lifts it onto the `ai_calls` row and
934
- * strips it before the response reaches callers.
968
+ * Observability only — `UniversalLLMAdapter` lifts it onto the `ai_calls` row. It is not removed
969
+ * from the response.
935
970
  */
936
971
  strictRefusalReasons?: string[];
937
972
  }
@@ -956,89 +991,84 @@ interface LLMAdapter {
956
991
  }
957
992
 
958
993
  /**
959
- * Memory type definitions
960
- * Types for agent memory management with semantic entry types
994
+ * Model Configuration
995
+ * Centralized model information, configuration, options, constraints, and validation
996
+ * Single source of truth for all model-related definitions
997
+ * Update manually when pricing changes or new models are added
961
998
  */
999
+
962
1000
  /**
963
- * Semantic memory entry types
964
- * Use-case agnostic types that describe the purpose of each entry
965
- * Memory types mirror action types for clarity and filtering
1001
+ * Supported Open AI models (direct SDK access)
966
1002
  */
967
- type MemoryEntryType = 'context' | 'input' | 'reasoning' | 'tool-result' | 'delegation-result' | 'error';
1003
+ type OpenAIModel = 'gpt-5' | 'gpt-5.4-mini' | 'gpt-5.4-nano';
968
1004
  /**
969
- * Who authored an entry's content.
970
- *
971
- * This is what lets the assembled prompt tell framework-authored text apart from text that
972
- * originated outside the trust boundary. `'framework'` content is ours; the other three are not
973
- * and are rendered inside the JSON data envelope (see `MemoryManager.toContextParts`).
1005
+ * Supported OpenRouter models (explicit union for type safety)
974
1006
  */
975
- type MemoryEntrySource = 'framework' | 'user' | 'tool' | 'model';
1007
+ type OpenRouterModel = 'openrouter/z-ai/glm-5';
976
1008
  /**
977
- * Memory entry - represents a single entry in agent memory
978
- * Stored in agent memory, translated by adapters to vendor-specific formats
1009
+ * Supported Anthropic models (direct SDK access via @anthropic-ai/sdk)
979
1010
  */
980
- interface MemoryEntry {
981
- type: MemoryEntryType;
982
- content: string;
983
- timestamp: number;
984
- turnNumber: number | null;
985
- iterationNumber: number | null;
986
- /**
987
- * Provenance. **Optional on purpose** — `undefined` means unknown, which is what every
988
- * pre-existing snapshot and every not-yet-redeployed tenant bundle produces. Read sites MUST
989
- * test `== null`, never `=== undefined`: the `inTurnScope` predicate in `manager.ts` is the
990
- * cautionary precedent, where a `=== undefined` check silently dropped every `null`-stamped
991
- * entry. `isMemoryEntry` is deliberately NOT tightened to require this field; doing so would
992
- * make every stored snapshot fail validation, and `restoreSessionMemory` fails open by
993
- * starting the agent with empty memory rather than throwing.
994
- */
995
- source?: MemoryEntrySource;
996
- }
1011
+ type AnthropicModel = 'claude-opus-5' | 'claude-sonnet-5' | 'claude-haiku-4-5-20251001' | 'claude-haiku-4-5';
1012
+ /** Supported LLM models */
1013
+ type LLMModel = OpenAIModel | OpenRouterModel | AnthropicModel | 'mock';
997
1014
  /**
998
- * Agent memory - Self-orchestrated memory with session + working storage
999
- * Agent has full control over what persists, framework handles auto-compaction
1015
+ * GPT-5 model options schema
1000
1016
  */
1001
- interface AgentMemory {
1002
- /**
1003
- * Session memory - Persists for session/conversation duration
1004
- * Never auto-trimmed by framework
1005
- * Agent-managed key-value store for critical information
1006
- * Agent provides strings, framework wraps in MemoryEntry
1007
- */
1008
- sessionMemory: Record<string, MemoryEntry>;
1009
- /**
1010
- * Working memory - Execution history
1011
- * Automatically compacted by framework when needed
1012
- * Agent doesn't control compaction
1013
- */
1014
- history: MemoryEntry[];
1015
- }
1017
+ declare const GPT5OptionsSchema: z.ZodObject<{
1018
+ reasoning_effort: z.ZodOptional<z.ZodEnum<{
1019
+ minimal: "minimal";
1020
+ low: "low";
1021
+ medium: "medium";
1022
+ high: "high";
1023
+ }>>;
1024
+ verbosity: z.ZodOptional<z.ZodEnum<{
1025
+ low: "low";
1026
+ medium: "medium";
1027
+ high: "high";
1028
+ }>>;
1029
+ }, z.core.$strip>;
1016
1030
  /**
1017
- * Memory status for agent awareness
1031
+ * OpenRouter model options schema
1032
+ * OpenRouter-specific options for routing and transforms
1018
1033
  */
1019
- interface MemoryStatus {
1020
- sessionMemoryKeys: number;
1021
- sessionMemoryLimit: number;
1022
- currentKeys: string[];
1023
- sessionMemoryTokens: number;
1024
- sessionMemoryTokenLimit: number;
1025
- /**
1026
- * History tokens as a percentage of `historyBudget` — history ALONE, not history plus session
1027
- * memory. It previously reported the combined total under this name, so session memory growth
1028
- * read as history pressure and triggered history compaction that could not relieve it.
1029
- */
1030
- historyPercent: number;
1031
- historyTokens: number;
1032
- historyBudget: number;
1033
- totalTokens: number;
1034
- tokenBudget: number;
1035
- }
1034
+ declare const OpenRouterOptionsSchema: z.ZodObject<{
1035
+ transforms: z.ZodOptional<z.ZodArray<z.ZodString>>;
1036
+ route: z.ZodOptional<z.ZodEnum<{
1037
+ fallback: "fallback";
1038
+ }>>;
1039
+ }, z.core.$strip>;
1036
1040
  /**
1037
- * Memory constraints (optional limits)
1041
+ * Anthropic model options schema
1042
+ * Currently empty - future options must be added per supported model family
1038
1043
  */
1039
- interface MemoryConstraints {
1040
- maxSessionMemoryKeys?: number;
1041
- maxMemoryTokens?: number;
1044
+ declare const AnthropicOptionsSchema: z.ZodObject<{}, z.core.$strict>;
1045
+ /**
1046
+ * Infer TypeScript types from schemas
1047
+ */
1048
+ type GPT5Options = z.infer<typeof GPT5OptionsSchema>;
1049
+ type MockOptions = Record<string, never>;
1050
+ type OpenRouterOptions = z.infer<typeof OpenRouterOptionsSchema>;
1051
+ type AnthropicOptions = z.infer<typeof AnthropicOptionsSchema>;
1052
+ type ModelSpecificOptions = GPT5Options | MockOptions | OpenRouterOptions | AnthropicOptions;
1053
+ /**
1054
+ * Model configuration for LLM execution
1055
+ * Belongs in resource definition (AgentDefinition, WorkflowDefinition, etc.)
1056
+ */
1057
+ interface ModelConfig {
1058
+ model: LLMModel;
1059
+ provider: 'openai' | 'anthropic' | 'openrouter' | 'mock';
1060
+ apiKey: string;
1061
+ temperature?: number;
1062
+ /** Maximum output tokens per LLM call. NOT the model's context window — see ModelInfo.maxTokens for that. */
1063
+ maxOutputTokens?: number;
1064
+ topP?: number;
1065
+ /**
1066
+ * Model-specific options (flat structure)
1067
+ * Options are model-specific, not vendor-specific
1068
+ * Available options defined in MODEL_INFO per model
1069
+ * Validated at build time via validateModelOptions()
1070
+ */
1071
+ modelOptions?: ModelSpecificOptions;
1042
1072
  }
1043
1073
 
1044
1074
  /**
@@ -1058,8 +1088,27 @@ interface MemoryConstraints {
1058
1088
  interface MemoryContextParts {
1059
1089
  /** Framework-authored. Memory status and a description of the envelope. Carries NO stored content. */
1060
1090
  framing: string;
1061
- /** Every stored fragment, JSON-encoded and source-tagged. Untrusted. */
1091
+ /** Every stored fragment, JSON-encoded. Untrusted. */
1062
1092
  dataEnvelope: string;
1093
+ /**
1094
+ * Union of prompt-injection warning types already found across every fragment `dataEnvelope`
1095
+ * actually carries this call, aggregated from verdicts stamped once when each fragment entered
1096
+ * memory (see `MemoryEntry.warnings`) rather than by re-scanning `dataEnvelope`'s text on every
1097
+ * iteration it gets rebuilt for. Elided fragments (see `ENVELOPE_FULL_RESULT_WINDOW`) contribute
1098
+ * nothing here — their original content isn't what gets sent once they're stubbed.
1099
+ *
1100
+ * This is metadata about the envelope, not part of it: folding a detector's own finding into the
1101
+ * model-visible JSON would hand a would-be attacker — plausibly the same person on the other end
1102
+ * of a session conversation — direct feedback on which pattern tripped. A caller wiring this up
1103
+ * (`screenRequest`'s `data-envelope` slot is the one that currently re-scans instead of reading
1104
+ * this) should treat it exactly the way `screenRequest` already treats cross-turn history: it
1105
+ * warns, but whether it blocks is that caller's decision to make, not this one's.
1106
+ *
1107
+ * Optional (not just possibly-empty): the fixture literals in `agent/reasoning/**` tests build
1108
+ * `MemoryContextParts` by hand without it, and requiring it would make this signature's landing
1109
+ * a forced edit across files this change does not otherwise touch.
1110
+ */
1111
+ envelopeWarnings?: string[];
1063
1112
  }
1064
1113
  /**
1065
1114
  * Memory Manager - Agent memory orchestration
@@ -1071,7 +1120,41 @@ declare class MemoryManager {
1071
1120
  private constraints;
1072
1121
  private logger?;
1073
1122
  private cachedSnapshot?;
1123
+ /**
1124
+ * Rolling correction for `estimateTokens`'s bias, learned from real provider usage.
1125
+ * `undefined` until the first `recordActualUsage` call -- the cold-start state, where
1126
+ * `estimate()` returns the raw `estimateTokens` output unscaled. See `recordActualUsage`.
1127
+ */
1128
+ private tokenCorrectionFactor?;
1074
1129
  constructor(memory: AgentMemory, constraints?: MemoryConstraints, logger?: AgentScopedLogger | undefined);
1130
+ /**
1131
+ * Record how far `estimateTokens` was from reality on a real provider call, and roll it into a
1132
+ * correction applied to every estimate this instance makes from here on -- `getStatus`'s three
1133
+ * token fields and `enforceSessionMemoryTokenLimit`'s eviction check, which is what
1134
+ * `autoCompact`/`enforceHardLimits` actually decide compaction from (C3 / Wave M3).
1135
+ *
1136
+ * `estimateTokens` is `chars / 3.5` -- a constant-ratio guess with no knowledge of JSON escaping,
1137
+ * key overhead, or real tokenizer behaviour. Every provider call already returns an EXACT count
1138
+ * (`usage.inputTokens`) that reaches `ai_calls` and is then dropped; this is where it stops being
1139
+ * dropped, without replacing the estimator outright -- a cold session still needs SOME number
1140
+ * before its first real call completes, so the estimator stays the prior and this only corrects
1141
+ * it once real data exists.
1142
+ *
1143
+ * `estimatedRequestTokens` must be `estimateTokens` applied to the SAME text `actualInputTokens`
1144
+ * was billed for -- the whole assembled request (system prompt, tools, conversation history, the
1145
+ * envelope, everything), not just what this class itself emits. `estimateTokens`'s bias is a
1146
+ * property of the heuristic, not of which slice of the request it is pointed at, so measuring it
1147
+ * against the full request (visible to the caller, not to this class) and applying the result to
1148
+ * this class's own estimates (which can only ever see its own slice) is a fair trade -- one ratio,
1149
+ * calibrated on real data, standing in for a per-segment breakdown nothing needs.
1150
+ *
1151
+ * Exponential moving average, not a straight replace: a single call's ratio is noisy, and a
1152
+ * straight replace lets one outlier swing every compaction decision made afterward. Each new
1153
+ * observation gets 30% weight, converging within a handful of calls without chasing one spike.
1154
+ */
1155
+ recordActualUsage(estimatedRequestTokens: number, actualInputTokens: number): void;
1156
+ /** `estimateTokens`, scaled by the learned correction once one exists. See `recordActualUsage`. */
1157
+ private estimate;
1075
1158
  /**
1076
1159
  * Set session memory entry (agent provides string, framework wraps it)
1077
1160
  * @param key - Session memory key
@@ -1113,6 +1196,14 @@ declare class MemoryManager {
1113
1196
  * are not. Eviction is oldest-first by timestamp, matching the key-count path, and always
1114
1197
  * leaves at least one entry so a single oversized key degrades to "one key" rather than to
1115
1198
  * "memory silently emptied".
1199
+ *
1200
+ * The running total is **recomputed** from the survivors rather than decremented per entry.
1201
+ * `getStatus` estimates the pool as a ceiling of the joined sum, and a per-entry decrement is a
1202
+ * sum of ceilings — the larger of the two by up to one token per key. The running total therefore
1203
+ * fell faster than the pool did, and the loop could exit reporting a fit while the very next
1204
+ * `getStatus` still read over the limit. Recomputing makes the loop's exit condition and the
1205
+ * number it is judged by the same expression. The pool is capped at `MAX_SESSION_MEMORY_KEYS`
1206
+ * entries, so the extra passes are bounded and cheap.
1116
1207
  */
1117
1208
  private enforceSessionMemoryTokenLimit;
1118
1209
  /**
@@ -1122,9 +1213,13 @@ declare class MemoryManager {
1122
1213
  getHistoryLength(): number;
1123
1214
  /**
1124
1215
  * Get memory status for agent awareness
1216
+ *
1217
+ * @param currentTurn - Turn to scope `historyTokens` / `historyPercent` to. Omit to measure the
1218
+ * whole store, which is what the compaction paths want. Callers building something the model
1219
+ * reads should pass it, so the count describes the set the model is actually handed.
1125
1220
  * @returns Memory status with token usage and key counts
1126
1221
  */
1127
- getStatus(): MemoryStatus;
1222
+ getStatus(currentTurn?: number): MemoryStatus;
1128
1223
  /**
1129
1224
  * Create memory snapshot for persistence
1130
1225
  * Caches snapshot internally for later retrieval
@@ -1155,7 +1250,15 @@ declare class MemoryManager {
1155
1250
  * treat "everything in this block" as data was also being handed the live question inside that
1156
1251
  * block.
1157
1252
  *
1158
- * Shows current iteration entries FIRST (reverse chronological) for LLM attention.
1253
+ * History entries stay chronological. They used to be split into a "current iteration" slot
1254
+ * (reverse chronological, for LLM positional bias) and an "earlier" slot -- but the LLM call
1255
+ * always happens BEFORE `addToHistory` writes that iteration's own entries, so the
1256
+ * current-iteration slot held nothing on any call that mattered. One chronological list replaces
1257
+ * both.
1258
+ *
1259
+ * Tool results (and tool errors) older than `ENVELOPE_FULL_RESULT_WINDOW` iterations are carried
1260
+ * as a short stub instead of their full content -- see `ENVELOPE_FULL_RESULT_WINDOW`. The STORE
1261
+ * (`this.memory.history`) is untouched; only what this call carries is capped.
1159
1262
  *
1160
1263
  * @param currentIteration - Current iteration number (0 = pre-iteration)
1161
1264
  * @param currentTurn - Current turn number (optional, for session context filtering)
@@ -1164,175 +1267,145 @@ declare class MemoryManager {
1164
1267
  }
1165
1268
 
1166
1269
  /**
1167
- * Knowledge Map Types
1168
- *
1169
- * Enables agents to navigate organizational knowledge through a lightweight
1170
- * graph that lazy-loads capabilities on-demand.
1171
- *
1172
- * @module agent/knowledge-map
1270
+ * Shared form field types for dynamic form generation
1271
+ * Used by: Command Queue, Execution Runner UI, future form-based features
1173
1272
  */
1273
+ /**
1274
+ * Supported form field types for action payloads
1275
+ * Maps to Mantine form components
1276
+ */
1277
+ type FormFieldType = 'text' | 'textarea' | 'number' | 'select' | 'checkbox' | 'radio' | 'richtext';
1278
+ /**
1279
+ * Form field definition
1280
+ */
1281
+ interface FormField {
1282
+ /** Field key in payload object */
1283
+ name: string;
1284
+ /** Field label for UI */
1285
+ label: string;
1286
+ /** Field type (determines UI component) */
1287
+ type: FormFieldType;
1288
+ /** Default value */
1289
+ defaultValue?: unknown;
1290
+ /** Required field */
1291
+ required?: boolean;
1292
+ /** Placeholder text */
1293
+ placeholder?: string;
1294
+ /** Help text */
1295
+ description?: string;
1296
+ /** Options for select/radio */
1297
+ options?: Array<{
1298
+ label: string;
1299
+ value: string | number;
1300
+ }>;
1301
+ /** Min/max for number */
1302
+ min?: number;
1303
+ max?: number;
1304
+ /** Path to context value for pre-filling (dot notation, e.g., 'proposal.summary') */
1305
+ defaultValueFromContext?: string;
1306
+ }
1307
+ /**
1308
+ * Form schema for action payload collection
1309
+ */
1310
+ interface FormSchema {
1311
+ /** Form title */
1312
+ title?: string;
1313
+ /** Form description */
1314
+ description?: string;
1315
+ /** Form fields */
1316
+ fields: FormField[];
1317
+ }
1174
1318
 
1175
1319
  /**
1176
- * Lightweight knowledge map (passed as agent property)
1177
- *
1178
- * Contains metadata about available knowledge nodes without loading
1179
- * the full content upfront. Total size: ~300-500 tokens.
1180
- *
1181
- * Multi-tenancy is enforced via:
1182
- * - File-scoped maps (organizations/{org-name}/knowledge/)
1183
- * - ExecutionContext.organizationId passed to node.load()
1320
+ * Execution interface configuration
1321
+ * Defines how a resource is executed via the UI (forms, scheduling, webhooks)
1322
+ * Applies to both agents and workflows
1184
1323
  */
1185
- interface KnowledgeMap {
1186
- /** Available knowledge nodes indexed by ID */
1187
- nodes: Record<string, KnowledgeNode>;
1324
+ interface ExecutionInterface {
1325
+ /** Form configuration for execution inputs */
1326
+ form: ExecutionFormSchema;
1327
+ /** Optional: Schedule configuration */
1328
+ schedule?: ScheduleConfig;
1329
+ /** Optional: Webhook trigger configuration */
1330
+ webhook?: WebhookConfig;
1188
1331
  }
1189
1332
  /**
1190
- * Single knowledge source
1191
- *
1192
- * Represents a domain knowledge area (CRM, brand guidelines, Excel tools)
1193
- * that can be lazy-loaded to provide instructions and tools to agents.
1333
+ * Execution form schema
1334
+ * Extends FormSchema with execution-specific fields
1194
1335
  */
1195
- interface KnowledgeNode {
1196
- /** Unique identifier for this node (e.g., "crm", "brand-guidelines") */
1197
- id: string;
1198
- /**
1199
- * Description of when to use this knowledge
1200
- * Used for semantic matching against user intent
1201
- */
1202
- description: string;
1203
- /**
1204
- * Load knowledge content on-demand
1205
- *
1206
- * @param context - Execution context with organizationId for multi-tenancy
1207
- * @returns Promise resolving to knowledge content (prompt + optional tools)
1208
- */
1209
- load(context: ExecutionContext): Promise<KnowledgeContent>;
1336
+ interface ExecutionFormSchema extends FormSchema {
1210
1337
  /**
1211
- * Loaded state flag
1212
- * Set to true after load() is called
1338
+ * Field mappings to resource input schema
1339
+ * Maps form field names to contract input paths
1340
+ * If omitted, field names must match contract input keys exactly
1213
1341
  */
1214
- loaded?: boolean;
1342
+ fieldMappings?: Record<string, string>;
1215
1343
  /**
1216
- * Cached prompt (for system prompt serialization)
1217
- * Only the prompt is cached - tools go to toolRegistry, children flattened to nodes
1344
+ * Submit button configuration
1345
+ * Default: { label: 'Run', loadingLabel: 'Running...' }
1218
1346
  */
1219
- prompt?: string;
1347
+ submitButton?: {
1348
+ label?: string;
1349
+ loadingLabel?: string;
1350
+ confirmMessage?: string;
1351
+ };
1220
1352
  }
1221
1353
  /**
1222
- * Content returned by knowledge node
1223
- *
1224
- * Separates instructions (prompt) from capabilities (tools).
1225
- * Tools are optional - some nodes only provide context.
1226
- *
1227
- * Supports recursive navigation - nodes can contain child nodes
1228
- * that are discovered when the parent node is loaded.
1229
- */
1230
- interface KnowledgeContent {
1231
- /** Instructions and context (markdown format) */
1232
- prompt: string;
1233
- /** Tool implementations (optional) */
1234
- tools?: Tool[];
1235
- /**
1236
- * Child knowledge nodes (optional, recursive)
1237
- *
1238
- * Enables hierarchical navigation: base → specialized → deep expertise.
1239
- * Child nodes are flattened into the main knowledge map when parent loads,
1240
- * making them available for subsequent navigate-knowledge actions.
1241
- *
1242
- * Example: CRM base node returns crm-customers and crm-deals as children
1243
- */
1244
- nodes?: Record<string, KnowledgeNode>;
1354
+ * Schedule configuration for automated execution
1355
+ */
1356
+ interface ScheduleConfig {
1357
+ /** Whether scheduling is enabled for this resource */
1358
+ enabled: boolean;
1359
+ /** Default schedule (cron expression) */
1360
+ defaultSchedule?: string;
1361
+ /** Allowed schedule patterns (if restricted) */
1362
+ allowedPatterns?: string[];
1245
1363
  }
1246
-
1247
1364
  /**
1248
- * Agent-specific type definitions
1249
- * Types for autonomous agents with tools, memory, and constraints
1365
+ * Webhook configuration for external triggers
1250
1366
  */
1367
+ interface WebhookConfig {
1368
+ /** Whether webhook trigger is enabled */
1369
+ enabled: boolean;
1370
+ /** Expected payload schema (for documentation) */
1371
+ payloadSchema?: unknown;
1372
+ }
1251
1373
 
1252
- /**
1253
- * Factory function for creating LLM adapters.
1254
- * Injected into the Agent class to decouple the engine from server-only provider SDKs.
1255
- * - API process: provides createLLMAdapter (real SDKs + process.env API keys)
1256
- * - SDK worker: provides PostMessageLLMAdapter (proxies via platform.call)
1257
- *
1258
- * Uses `any` for optional params so both the real createLLMAdapter (with typed
1259
- * AIUsageCollector/AICallContext) and the worker proxy (which ignores them) satisfy the type.
1260
- */
1261
- type LLMAdapterFactory = (config: ModelConfig, ...args: any[]) => LLMAdapter;
1262
- type AgentKind = 'orchestrator' | 'specialist' | 'utility' | 'platform';
1263
- interface AgentConfig extends ResourceDefinition {
1264
- type: 'agent';
1374
+ interface WorkflowConfig extends ResourceDefinition {
1375
+ type: 'workflow';
1265
1376
  /** OM descriptor backing canonical identity and governance metadata. */
1266
- resource?: AgentResourceEntry;
1267
- kind: AgentKind;
1268
- systemPrompt: string;
1269
- constraints?: AgentConstraints;
1270
- /**
1271
- * Session capability declaration (opt-in)
1272
- * If true, agent is designed for multi-turn session interactions
1273
- * Controls whether agent can use message action and appears in Sessions UI
1274
- *
1275
- * Use for:
1276
- * - Conversational agents with multi-turn interactions
1277
- * - Agents requiring persistent context across turns
1278
- * - Agents that need human-in-the-loop communication
1279
- */
1280
- sessionCapable?: boolean;
1281
- /**
1282
- * Security level for system prompt hardening (auto-derived if omitted)
1283
- *
1284
- * - 'standard': Lightweight defense (3 rules) - default for non-session agents
1285
- * - 'hardened': Comprehensive defense (5 rules) - default for session-capable agents
1286
- * - 'none': No security prompt - for pure internal agents with no external input
1287
- *
1288
- * If omitted, derived from sessionCapable:
1289
- * sessionCapable: true -> 'hardened'
1290
- * sessionCapable: false -> 'standard'
1291
- */
1292
- securityLevel?: 'standard' | 'hardened' | 'none';
1293
- /**
1294
- * Memory management preferences (opt-in)
1295
- * If provided, agent can use memoryOps to manage session memory
1296
- * If omitted, agent has no memory management capabilities
1297
- *
1298
- * Agent-specific guidance on what to preserve, when to persist, and what to clean up.
1299
- * This guidance is injected into the system prompt when memory management is enabled.
1300
- *
1301
- * Use for:
1302
- * - Conversational agents needing cross-turn context
1303
- * - Agents managing complex user preferences
1304
- * - Agents tracking decisions over multiple iterations
1305
- */
1306
- memoryPreferences?: string;
1377
+ resource?: WorkflowResourceEntry;
1378
+ }
1379
+ interface WorkflowStepDefinition {
1380
+ id: string;
1381
+ name: string;
1382
+ description: string;
1383
+ }
1384
+ type StepHandler = (input: unknown, context: ExecutionContext) => Promise<unknown>;
1385
+ interface LinearNext {
1386
+ type: 'linear';
1387
+ target: string;
1307
1388
  }
1308
- interface AgentConstraints {
1309
- maxIterations?: number;
1310
- timeout?: number;
1311
- maxSessionMemoryKeys?: number;
1312
- maxMemoryTokens?: number;
1389
+ interface ConditionalNext {
1390
+ type: 'conditional';
1391
+ routes: Array<{
1392
+ condition: (data: unknown) => boolean;
1393
+ target: string;
1394
+ }>;
1395
+ default: string;
1313
1396
  }
1314
- interface AgentDefinition {
1315
- config: AgentConfig;
1397
+ type NextConfig = LinearNext | ConditionalNext | null;
1398
+ interface WorkflowStep extends WorkflowStepDefinition {
1399
+ handler: StepHandler;
1400
+ inputSchema: z.ZodSchema;
1401
+ outputSchema: z.ZodSchema;
1402
+ next: NextConfig;
1403
+ }
1404
+ interface WorkflowDefinition {
1405
+ config: WorkflowConfig;
1316
1406
  contract: Contract;
1317
- tools: Tool[];
1318
- /**
1319
- * Model configuration for LLM execution
1320
- * Specifies provider, API key, and model-specific options
1321
- */
1322
- modelConfig: ModelConfig;
1323
- /**
1324
- * Optional knowledge map for lazy-loading capabilities
1325
- * Enables agents to navigate organizational knowledge on-demand
1326
- */
1327
- knowledgeMap?: KnowledgeMap;
1328
- /**
1329
- * Preload memory before execution starts
1330
- * Handles BOTH context loading AND session restoration
1331
- *
1332
- * @param context - Execution context (includes sessionId if session turn)
1333
- * @returns Initial AgentMemory state (sessionMemory entries + optionally history)
1334
- */
1335
- preloadMemory?: (context: ExecutionContext) => Promise<AgentMemory> | AgentMemory;
1407
+ steps: Record<string, WorkflowStep>;
1408
+ entryPoint: string;
1336
1409
  /**
1337
1410
  * Metrics configuration for ROI calculations
1338
1411
  * Optional: Only needed if tracking automation savings
@@ -1340,31 +1413,19 @@ interface AgentDefinition {
1340
1413
  metricsConfig?: ResourceMetricsConfig;
1341
1414
  /**
1342
1415
  * Execution interface configuration (optional)
1343
- * If provided, agent appears in Execution Runner UI
1416
+ * If provided, workflow appears in Execution Runner UI
1344
1417
  */
1345
1418
  interface?: ExecutionInterface;
1346
- }
1347
- /**
1348
- * Agent execution context
1349
- * Groups all state needed for agent execution phases
1350
- */
1351
- interface IterationContext {
1352
- config: AgentConfig;
1353
- contract: Contract;
1354
- toolRegistry: Map<string, Tool>;
1355
- memoryManager: MemoryManager;
1356
- executionContext: ExecutionContext;
1357
- iteration: number;
1358
- logger: AgentScopedLogger;
1359
- modelConfig: ModelConfig;
1360
- adapterFactory: LLMAdapterFactory;
1361
- knowledgeMap?: KnowledgeMap;
1362
1419
  /**
1363
- * The validated input for this execution, serialized. It travels here because the model gets
1364
- * it as its own `role:'user'` message; nothing else in this context carried it, so the input
1365
- * had to be read back out of memory history and shipped inside the memory block.
1420
+ * Lead-gen processing stage this workflow implements (optional).
1421
+ * Must match a key in the platform lead-gen stage catalog.
1422
+ * Used by org-os graph derivation to surface workflow→stage edges and
1423
+ * by pipeline_config validation to confirm each catalog stage has an
1424
+ * implementing workflow before a list is activated.
1425
+ *
1426
+ * Example: stageImplemented: 'verified' on the email-verification workflow.
1366
1427
  */
1367
- currentInput: string;
1428
+ stageImplemented?: string;
1368
1429
  }
1369
1430
 
1370
1431
  type Json = string | number | boolean | null | {
@@ -7397,6 +7458,32 @@ type StorageDownloadOutput = z.infer<typeof StorageDownloadOutputSchema>;
7397
7458
  type StorageDeleteOutput = z.infer<typeof StorageDeleteOutputSchema>;
7398
7459
  type StorageListOutput = z.infer<typeof StorageListOutputSchema>;
7399
7460
 
7461
+ /**
7462
+ * AIUsageCollector
7463
+ * Centralized token tracking that aggregates usage across all LLM calls in an execution
7464
+ */
7465
+ declare class AIUsageCollector {
7466
+ private model;
7467
+ private calls;
7468
+ private callSequence;
7469
+ /**
7470
+ * Record a single AI call with usage metrics
7471
+ *
7472
+ * @param usage - Token usage and latency data from LLM adapter
7473
+ * @param callType - Type discriminator (agent-reasoning, tool, etc.)
7474
+ * @param context - Optional typed context specific to callType
7475
+ */
7476
+ record(usage: LLMUsageData, callType?: BaseAICall['callType'], context?: AICallContext): void;
7477
+ /**
7478
+ * Get aggregated summary of all AI calls
7479
+ */
7480
+ getSummary(): AIUsageSummary;
7481
+ /**
7482
+ * Check if any usage has been recorded
7483
+ */
7484
+ hasUsage(): boolean;
7485
+ }
7486
+
7400
7487
  /**
7401
7488
  * Create record parameters
7402
7489
  */
@@ -8955,9 +9042,9 @@ declare const ProjectSchemas: {
8955
9042
  CreateProjectRequest: z.ZodObject<{
8956
9043
  name: z.ZodString;
8957
9044
  kind: z.ZodEnum<{
8958
- internal: "internal";
8959
9045
  other: "other";
8960
9046
  client_engagement: "client_engagement";
9047
+ internal: "internal";
8961
9048
  research: "research";
8962
9049
  }>;
8963
9050
  status: z.ZodOptional<z.ZodEnum<{
@@ -8980,9 +9067,9 @@ declare const ProjectSchemas: {
8980
9067
  UpdateProjectRequest: z.ZodObject<{
8981
9068
  name: z.ZodOptional<z.ZodString>;
8982
9069
  kind: z.ZodOptional<z.ZodEnum<{
8983
- internal: "internal";
8984
9070
  other: "other";
8985
9071
  client_engagement: "client_engagement";
9072
+ internal: "internal";
8986
9073
  research: "research";
8987
9074
  }>>;
8988
9075
  status: z.ZodOptional<z.ZodEnum<{
@@ -9005,9 +9092,9 @@ declare const ProjectSchemas: {
9005
9092
  }, z.core.$strict>;
9006
9093
  GetProjectsQuery: z.ZodObject<{
9007
9094
  kind: z.ZodOptional<z.ZodEnum<{
9008
- internal: "internal";
9009
9095
  other: "other";
9010
9096
  client_engagement: "client_engagement";
9097
+ internal: "internal";
9011
9098
  research: "research";
9012
9099
  }>>;
9013
9100
  status: z.ZodOptional<z.ZodEnum<{
@@ -9095,12 +9182,12 @@ declare const ProjectSchemas: {
9095
9182
  status: z.ZodOptional<z.ZodEnum<{
9096
9183
  completed: "completed";
9097
9184
  cancelled: "cancelled";
9185
+ rejected: "rejected";
9098
9186
  blocked: "blocked";
9099
9187
  in_progress: "in_progress";
9100
9188
  planned: "planned";
9101
9189
  submitted: "submitted";
9102
9190
  approved: "approved";
9103
- rejected: "rejected";
9104
9191
  revision_requested: "revision_requested";
9105
9192
  }>>;
9106
9193
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -9131,12 +9218,12 @@ declare const ProjectSchemas: {
9131
9218
  status: z.ZodOptional<z.ZodEnum<{
9132
9219
  completed: "completed";
9133
9220
  cancelled: "cancelled";
9221
+ rejected: "rejected";
9134
9222
  blocked: "blocked";
9135
9223
  in_progress: "in_progress";
9136
9224
  planned: "planned";
9137
9225
  submitted: "submitted";
9138
9226
  approved: "approved";
9139
- rejected: "rejected";
9140
9227
  revision_requested: "revision_requested";
9141
9228
  }>>;
9142
9229
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -9158,12 +9245,12 @@ declare const ProjectSchemas: {
9158
9245
  status: z.ZodOptional<z.ZodEnum<{
9159
9246
  completed: "completed";
9160
9247
  cancelled: "cancelled";
9248
+ rejected: "rejected";
9161
9249
  blocked: "blocked";
9162
9250
  in_progress: "in_progress";
9163
9251
  planned: "planned";
9164
9252
  submitted: "submitted";
9165
9253
  approved: "approved";
9166
- rejected: "rejected";
9167
9254
  revision_requested: "revision_requested";
9168
9255
  }>>;
9169
9256
  milestone_id: z.ZodOptional<z.ZodString>;
@@ -10304,6 +10391,17 @@ interface BaseAICall {
10304
10391
  costUsd: number;
10305
10392
  latencyMs: number;
10306
10393
  context?: AICallContext;
10394
+ /**
10395
+ * Anthropic-only: input tokens served from the prompt cache this call (`cache_read_input_tokens`),
10396
+ * billed at 0.1x the base input rate. Already folded into `inputTokens`/`totalInputTokens` so
10397
+ * aggregate totals reflect real usage -- present here as the raw breakdown, not additive on top.
10398
+ */
10399
+ cacheReadInputTokens?: number;
10400
+ /**
10401
+ * Anthropic-only: input tokens written to the prompt cache this call (`cache_creation_input_tokens`),
10402
+ * billed at 1.25x the base input rate. Same folding rationale as `cacheReadInputTokens`.
10403
+ */
10404
+ cacheCreationInputTokens?: number;
10307
10405
  /**
10308
10406
  * Distinct prompt-injection pattern types detected in the request's user-role messages.
10309
10407
  * Present only when the input sanitizer matched something. Non-blocking matches ride along on
@@ -10369,6 +10467,41 @@ interface BaseAICall {
10369
10467
  * Existing readers that only look at the fields above are unaffected.
10370
10468
  */
10371
10469
  strictRefusalReasons?: string[];
10470
+ /**
10471
+ * Time spent in the base adapter's `generate()` call alone, excluding `responseSchema`
10472
+ * validation. On a success or validation-failure row, `providerMs + validateMs === latencyMs`
10473
+ * (modulo rounding) -- `latencyMs` keeps its existing meaning unchanged; this and `validateMs`
10474
+ * are the same window split into its two components.
10475
+ *
10476
+ * Present on success and validation-failure rows. Absent on a blocked row (no provider call was
10477
+ * made) and on rows written before this field existed.
10478
+ */
10479
+ providerMs?: number;
10480
+ /**
10481
+ * Time spent in `validateResponseSchema` alone. Omitted when the call carried no `responseSchema`
10482
+ * (nothing to validate); `0` is a legitimate value meaning a schema was supplied and validation
10483
+ * was effectively instant. See `providerMs` for how the two relate to `latencyMs`.
10484
+ *
10485
+ * Present on success and validation-failure rows that supplied a `responseSchema`. Absent on a
10486
+ * blocked row and on rows written before this field existed.
10487
+ */
10488
+ validateMs?: number;
10489
+ /**
10490
+ * Total elapsed time for the WHOLE `generate()` call -- every retry attempt plus every backoff
10491
+ * sleep between them. Unlike `latencyMs` (which is per-attempt and never includes backoff, by
10492
+ * design -- see `runWithRetry`), this is the one number that answers "how long did the caller
10493
+ * actually wait". On a call that never retried, `wallClockMs === latencyMs`. On a retried call,
10494
+ * `wallClockMs` is strictly greater than any individual row's `latencyMs` from that same call, by
10495
+ * at least the backoff time actually slept.
10496
+ *
10497
+ * The same value is attached to every row produced by one `generate()` call (a validation-failure
10498
+ * row from an earlier attempt included), because it describes the call, not the attempt.
10499
+ *
10500
+ * Present on success and validation-failure rows. Absent on a blocked row -- a blocked call never
10501
+ * reaches the retry loop, so `wallClockMs` would just restate `latencyMs` (0). Absent on rows
10502
+ * written before this field existed.
10503
+ */
10504
+ wallClockMs?: number;
10372
10505
  }
10373
10506
  type AICallContext = AgentReasoningContext | AgentCompletionContext | WorkflowStepContext | ToolCallContext | OtherCallContext;
10374
10507
  interface AgentReasoningContext {
@@ -10414,6 +10547,16 @@ interface LLMUsageData {
10414
10547
  latencyMs: number;
10415
10548
  /** Actual cost from provider in USD (when available, e.g., OpenRouter) */
10416
10549
  cost?: number;
10550
+ /**
10551
+ * Anthropic-only: input tokens served from the prompt cache (`cache_read_input_tokens`), billed at
10552
+ * 0.1x the base input rate. Absent for providers that never report it (OpenAI, OpenRouter).
10553
+ */
10554
+ cacheReadInputTokens?: number;
10555
+ /**
10556
+ * Anthropic-only: input tokens written to the prompt cache this call
10557
+ * (`cache_creation_input_tokens`), billed at 1.25x the base input rate. Same absence rationale.
10558
+ */
10559
+ cacheCreationInputTokens?: number;
10417
10560
  /** Distinct prompt-injection pattern types detected in the request's user-role messages */
10418
10561
  inputWarnings?: string[];
10419
10562
  /** Additive per-source breakdown of `inputWarnings` — see `SourcedInputWarnings` */
@@ -10428,6 +10571,12 @@ interface LLMUsageData {
10428
10571
  strictStatus?: StrictStatus;
10429
10572
  /** Why the call went out unstrict, when a strict-capable adapter refused the schema */
10430
10573
  strictRefusalReasons?: string[];
10574
+ /** Time in the base adapter's `generate()` alone, excluding `responseSchema` validation. See `BaseAICall.providerMs`. */
10575
+ providerMs?: number;
10576
+ /** Time in `validateResponseSchema` alone. Omitted when no `responseSchema` was supplied. See `BaseAICall.validateMs`. */
10577
+ validateMs?: number;
10578
+ /** Total elapsed for the whole `generate()` call, including every retry and every backoff sleep. See `BaseAICall.wallClockMs`. */
10579
+ wallClockMs?: number;
10431
10580
  }
10432
10581
  interface AIUsageSummary {
10433
10582
  model: LLMModel;
@@ -10450,29 +10599,147 @@ interface ResourceMetricsConfig {
10450
10599
  }
10451
10600
 
10452
10601
  /**
10453
- * AIUsageCollector
10454
- * Centralized token tracking that aggregates usage across all LLM calls in an execution
10602
+ * Agent-specific type definitions
10603
+ * Types for autonomous agents with tools, memory, and constraints
10455
10604
  */
10456
- declare class AIUsageCollector {
10457
- private model;
10458
- private calls;
10459
- private callSequence;
10605
+
10606
+ /**
10607
+ * Factory function for creating LLM adapters.
10608
+ * Injected into the Agent class to decouple the engine from server-only provider SDKs.
10609
+ * - API process: provides createLLMAdapter (real SDKs + process.env API keys)
10610
+ * - SDK worker: provides PostMessageLLMAdapter (proxies via platform.call)
10611
+ *
10612
+ * Uses `any` for optional params so both the real createLLMAdapter (with typed
10613
+ * AIUsageCollector/AICallContext) and the worker proxy (which ignores them) satisfy the type.
10614
+ */
10615
+ type LLMAdapterFactory = (config: ModelConfig, ...args: any[]) => LLMAdapter;
10616
+ type AgentKind = 'orchestrator' | 'specialist' | 'utility' | 'platform';
10617
+ interface AgentConfig extends ResourceDefinition {
10618
+ type: 'agent';
10619
+ /** OM descriptor backing canonical identity and governance metadata. */
10620
+ resource?: AgentResourceEntry;
10621
+ kind: AgentKind;
10622
+ systemPrompt: string;
10623
+ constraints?: AgentConstraints;
10460
10624
  /**
10461
- * Record a single AI call with usage metrics
10625
+ * Session capability declaration (opt-in)
10626
+ * If true, agent is designed for multi-turn session interactions
10627
+ * Controls whether agent can use message action and appears in Sessions UI
10462
10628
  *
10463
- * @param usage - Token usage and latency data from LLM adapter
10464
- * @param callType - Type discriminator (agent-reasoning, tool, etc.)
10465
- * @param context - Optional typed context specific to callType
10629
+ * Use for:
10630
+ * - Conversational agents with multi-turn interactions
10631
+ * - Agents requiring persistent context across turns
10632
+ * - Agents that need human-in-the-loop communication
10466
10633
  */
10467
- record(usage: LLMUsageData, callType?: BaseAICall['callType'], context?: AICallContext): void;
10634
+ sessionCapable?: boolean;
10468
10635
  /**
10469
- * Get aggregated summary of all AI calls
10636
+ * Overrides the default `message` requiredness for a session-capable agent (ignored for
10637
+ * non-session agents, which always get `AgentCapabilities.message: 'off'`). Defaults to
10638
+ * `'required'` -- see `AgentCapabilities.message`'s doc comment for why. Set `'optional'` only
10639
+ * when the agent legitimately needs tool-only turns with no reply, and the deploy target can
10640
+ * tolerate the blind-retry risk `validateResponseSchema` carries on any path where the schema is
10641
+ * not compiled into a sampling grammar.
10470
10642
  */
10471
- getSummary(): AIUsageSummary;
10643
+ messagePolicy?: 'optional' | 'required';
10472
10644
  /**
10473
- * Check if any usage has been recorded
10645
+ * Explicit opt-in to skip the iteration loop and produce `contract.outputSchema`-shaped output in
10646
+ * a single LLM call (round 3 decision B6: explicit opt-in, never inferred from `kind`,
10647
+ * `sessionCapable`, or tool count -- so no existing agent changes shape by default). Structurally
10648
+ * the normal path pays two calls minimum: `iterate()` always runs at least one, and `complete()`
10649
+ * runs a second whose prompt re-derives the answer from history rather than reading what the
10650
+ * iteration already decided. A single-shot classifier -- one input in, one structured output out,
10651
+ * no multi-step reasoning needed -- does not need that second derivation; `complete()` already
10652
+ * makes exactly the one call it needs, from `currentInput` directly.
10653
+ *
10654
+ * Requires `sessionCapable` to be falsy and `contract.outputSchema` to be present. `Agent`
10655
+ * validates both during initialization and throws `AgentInitializationError` if either is missing,
10656
+ * rather than silently falling back to the normal two-call path on a misconfigured opt-in. Tools
10657
+ * registered on the agent are never invoked in this path -- there is no iteration loop to call
10658
+ * them from, so an agent that needs tool calls before it can answer is not eligible regardless of
10659
+ * this flag.
10474
10660
  */
10475
- hasUsage(): boolean;
10661
+ singleShot?: boolean;
10662
+ /**
10663
+ * Security level for system prompt hardening (auto-derived if omitted)
10664
+ *
10665
+ * - 'standard': Lightweight defense (3 rules) - default for non-session agents
10666
+ * - 'hardened': Comprehensive defense (5 rules) - default for session-capable agents
10667
+ * - 'none': No security prompt - for pure internal agents with no external input
10668
+ *
10669
+ * If omitted, derived from sessionCapable:
10670
+ * sessionCapable: true -> 'hardened'
10671
+ * sessionCapable: false -> 'standard'
10672
+ */
10673
+ securityLevel?: 'standard' | 'hardened' | 'none';
10674
+ /**
10675
+ * Memory management preferences (opt-in)
10676
+ * If provided, agent can use memoryOps to manage session memory
10677
+ * If omitted, agent has no memory management capabilities
10678
+ *
10679
+ * Agent-specific guidance on what to preserve, when to persist, and what to clean up.
10680
+ * This guidance is injected into the system prompt when memory management is enabled.
10681
+ *
10682
+ * Use for:
10683
+ * - Conversational agents needing cross-turn context
10684
+ * - Agents managing complex user preferences
10685
+ * - Agents tracking decisions over multiple iterations
10686
+ */
10687
+ memoryPreferences?: string;
10688
+ }
10689
+ interface AgentConstraints {
10690
+ maxIterations?: number;
10691
+ timeout?: number;
10692
+ maxSessionMemoryKeys?: number;
10693
+ maxMemoryTokens?: number;
10694
+ }
10695
+ interface AgentDefinition {
10696
+ config: AgentConfig;
10697
+ contract: Contract;
10698
+ tools: Tool[];
10699
+ /**
10700
+ * Model configuration for LLM execution
10701
+ * Specifies provider, API key, and model-specific options
10702
+ */
10703
+ modelConfig: ModelConfig;
10704
+ /**
10705
+ * Preload memory before execution starts
10706
+ * Handles BOTH context loading AND session restoration
10707
+ *
10708
+ * @param context - Execution context (includes sessionId if session turn)
10709
+ * @returns Initial AgentMemory state (sessionMemory entries + optionally history)
10710
+ */
10711
+ preloadMemory?: (context: ExecutionContext) => Promise<AgentMemory> | AgentMemory;
10712
+ /**
10713
+ * Metrics configuration for ROI calculations
10714
+ * Optional: Only needed if tracking automation savings
10715
+ */
10716
+ metricsConfig?: ResourceMetricsConfig;
10717
+ /**
10718
+ * Execution interface configuration (optional)
10719
+ * If provided, agent appears in Execution Runner UI
10720
+ */
10721
+ interface?: ExecutionInterface;
10722
+ }
10723
+ /**
10724
+ * Agent execution context
10725
+ * Groups all state needed for agent execution phases
10726
+ */
10727
+ interface IterationContext {
10728
+ config: AgentConfig;
10729
+ contract: Contract;
10730
+ toolRegistry: Map<string, Tool>;
10731
+ memoryManager: MemoryManager;
10732
+ executionContext: ExecutionContext;
10733
+ iteration: number;
10734
+ logger: AgentScopedLogger;
10735
+ modelConfig: ModelConfig;
10736
+ adapterFactory: LLMAdapterFactory;
10737
+ /**
10738
+ * The validated input for this execution, serialized. It travels here because the model gets
10739
+ * it as its own `role:'user'` message; nothing else in this context carried it, so the input
10740
+ * had to be read back out of memory history and shipped inside the memory block.
10741
+ */
10742
+ currentInput: string;
10476
10743
  }
10477
10744
 
10478
10745
  /**
@@ -10620,6 +10887,19 @@ interface Tool {
10620
10887
  outputSchema: z.ZodSchema;
10621
10888
  execute: (options: ToolExecutionOptions) => Promise<unknown>;
10622
10889
  timeout?: number;
10890
+ /**
10891
+ * Optional per-tool output size bound, in approximate tokens. Today the ONLY size bound on tool
10892
+ * output is a 4,000-token truncation applied post-hoc at memory insert -- after the payload is
10893
+ * already fully materialized, validated against `outputSchema`, emitted as a session message, and
10894
+ * logged. This field exists so a tool can declare its own bound up front instead.
10895
+ *
10896
+ * Enforcement is NOT here. `executor.ts:executeToolCall` is the single call site that produces the
10897
+ * value handed to all four sinks (memory, the `agent:tool_result` event, the session message, and
10898
+ * the log line) -- enforcing there, before that value is emitted, is what makes the four sinks agree
10899
+ * instead of three of them seeing the untruncated payload. See that file's own comment for the
10900
+ * exact insertion point.
10901
+ */
10902
+ maxOutputTokens?: number;
10623
10903
  }
10624
10904
 
10625
10905
  /**
@@ -10988,19 +11268,17 @@ interface DeploymentSpec {
10988
11268
  * Types are shared with the server-side LLM engine and inlined for SDK consumers.
10989
11269
  */
10990
11270
 
10991
- type LLMProvider = 'openai' | 'anthropic' | 'openrouter' | 'google';
11271
+ type LLMProvider = 'openai' | 'anthropic' | 'openrouter';
10992
11272
  /**
10993
11273
  * SDK LLM generate params.
10994
11274
  * Extends LLMGenerateRequest with required provider/model for worker→platform dispatch.
10995
11275
  * Provider and model must always be specified explicitly — no implicit fallback.
10996
11276
  */
10997
- interface SDKLLMGenerateParams extends Omit<LLMGenerateRequest, 'signal' | 'responseSchema'> {
11277
+ interface SDKLLMGenerateParams extends Omit<LLMGenerateRequest, 'signal'> {
10998
11278
  /** LLM provider */
10999
11279
  provider: LLMProvider;
11000
11280
  /** Model identifier — must be a supported LLMModel */
11001
11281
  model: LLMModel;
11002
- /** JSON Schema for structured output (optional — omit for unstructured text) */
11003
- responseSchema?: unknown;
11004
11282
  }
11005
11283
 
11006
11284
  /**
@@ -11045,7 +11323,10 @@ type TypedAdapter<TMap extends ToolMethodMap$1> = {
11045
11323
  * parentExecutionId?, executionDepth }
11046
11324
  * Worker -> Parent: { type: 'result', status, output?, memorySnapshot?, error?, logs, metrics: { durationMs } }
11047
11325
  *
11048
- * Parent -> Worker: { type: 'abort' } (graceful abort before terminate)
11326
+ * Parent -> Worker: { type: 'abort', reason? } (graceful abort before terminate;
11327
+ * reason carries AbortSignal.reason
11328
+ * across the boundary -- see N6, agent-
11329
+ * framework-round-3.mdx)
11049
11330
  *
11050
11331
  * Worker -> Parent: { type: 'log', entry: { level, message, timestamp, executionId, context? } }
11051
11332
  *