@tangle-network/agent-runtime 0.75.1 → 0.76.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.
package/dist/index.d.ts CHANGED
@@ -2,11 +2,11 @@ import { AgentProfile, AgentEvalError, AnalystFinding, KnowledgeReadinessReport,
2
2
  export { AgentEvalError, AgentEvalErrorCode, ConfigError, ControlBudget, ControlDecision, ControlEvalResult, ControlRunResult, ControlStep, DataAcquisitionPlan, JudgeError, KnowledgeReadinessReport, KnowledgeRequirement, NotFoundError, RunRecord, ValidationError } from '@tangle-network/agent-eval';
3
3
  import { f as AgentBackendInput, g as AgentExecutionBackend, O as OpenAIChatTool, h as OpenAIChatToolChoice, i as OpenAIChatResponseFormat, j as AgentBackendContext, a as RuntimeStreamEvent, K as KnowledgeReadinessDecision, k as RunAgentTaskOptions, l as AgentTaskRunResult, m as RunAgentTaskStreamOptions, n as AgentRuntimeEvent, o as AgentTaskStatus, p as RuntimeSessionStore, q as RuntimeSession, R as RuntimeHooks } from './types-B-jWSfcu.js';
4
4
  export { r as AgentAdapter, s as AgentKnowledgeProvider, t as AgentRuntimeEventSink, u as AgentTaskContext, v as AgentTaskSpec, B as BackendErrorDetail, w as RuntimeDecisionEvidenceRef, x as RuntimeDecisionKind, y as RuntimeDecisionPoint, z as RuntimeHookContext, C as RuntimeHookErrorContext, D as RuntimeHookEvent, F as RuntimeHookPhase, G as RuntimeHookTarget, H as RuntimeRunHandle, J as RuntimeRunPersistenceAdapter, M as RuntimeRunRow, N as composeRuntimeHooks, P as defineRuntimeHooks, Q as notifyRuntimeDecisionPoint, T as notifyRuntimeHookEvent, U as startRuntimeRun } from './types-B-jWSfcu.js';
5
- import { AgentProfile as AgentProfile$1 } from '@tangle-network/agent-interface';
6
5
  import { Scenario, ProfileDispatchFn } from '@tangle-network/agent-eval/campaign';
7
6
  import { C as CandidateGenerator } from './mcp-serve-verifier-CT1KLTG_.js';
8
7
  export { A as AgenticGeneratorOptions, I as ImprovementDriverOptions, M as McpServeSpec, V as Verifier, a as VerifyResult, b as agenticGenerator, c as commandVerifier, i as improvementDriver, m as mcpServeVerifier } from './mcp-serve-verifier-CT1KLTG_.js';
9
8
  import { Scenario as Scenario$1, SurfaceProposer, JudgeConfig, MutableSurface, DispatchContext, SelfImproveBudget, SelfImproveLlm, SelfImproveResult } from '@tangle-network/agent-eval/contract';
9
+ import { AgentProfile as AgentProfile$1 } from '@tangle-network/agent-interface';
10
10
  import { S as SurfaceImprovementEdit } from './improvement-adapter-CioiEE2z.js';
11
11
  import { I as ImprovementAdapter } from './types-BC3bZpH0.js';
12
12
  export { D as DELEGATED_LOOP_MODES, a as DelegatedLoopMode, b as DelegatedLoopRegistry, c as DelegatedLoopResult, d as DelegatedLoopRunner, L as LoopRunnerCliArgs, e as LoopRunnerCliResult, R as ResearchLoopResult, f as ResearchLoopRunnerOptions, g as RunDelegatedLoopOptions, V as VetoedFact, W as WorktreeLoopRunnerOptions, h as auditLoopRunner, i as isDelegatedLoopMode, p as parseLoopRunnerArgv, r as researchLoopRunner, j as runDelegatedLoop, k as runLoopRunnerCli, s as selfImproveLoopRunner, w as worktreeLoopRunner } from './loop-runner-bin-Dbtg787n.js';
@@ -675,144 +675,6 @@ declare function defineConversation(input: {
675
675
  policy: ConversationPolicy;
676
676
  }): Conversation;
677
677
 
678
- /**
679
- * `runPersonaConversation` — the persona loop runner: run a WORKER `AgentProfile`
680
- * (the agent under test) as a multi-round conversation driven by a PERSONA (the
681
- * simulated user), over the persistent conversation transcript.
682
- *
683
- * It is profiles-vs-profiles: the persona is itself a driver `AgentProfile` (an
684
- * LLM role-playing the user from its facts) — `runConversation` runs the two
685
- * against each other. Scripted persona turns are kept as a deterministic
686
- * fast-path. Only the WORKER is metered (it is the side under test); the
687
- * persona-driver is the test harness, not billed against the agent.
688
- *
689
- * `runPersonaDispatch` wraps the runner as a `ProfileDispatchFn` so it drops
690
- * straight into `runProfileMatrix({ dispatch })` — the same loop serves a single
691
- * cell and the whole matrix, replacing the per-agent hand-rolled
692
- * `dispatchWithSurface` bridges.
693
- */
694
-
695
- /** A persona that drives the conversation: either a full driver `AgentProfile`
696
- * (an LLM user-sim) or a deterministic script of user turns (the fast-path). */
697
- type PersonaDriver = {
698
- kind: 'profile';
699
- profile: AgentProfile;
700
- } | {
701
- kind: 'scripted';
702
- turns: string[];
703
- };
704
- interface RunPersonaConversationOptions {
705
- /** The agent under test. Metered; its rendered prompt leads its turns. */
706
- worker: AgentProfile;
707
- /** The simulated user driving the dialogue. */
708
- persona: PersonaDriver;
709
- /** Turn an `AgentProfile` into a runnable backend (router / sandbox / fake).
710
- * Applied to the worker and to a `profile`-kind persona. */
711
- backendFor: (profile: AgentProfile, role: 'worker' | 'persona') => AgentExecutionBackend;
712
- /** Render a profile's system prompt — prepended to that profile's messages. */
713
- systemPromptOf: (profile: AgentProfile) => string;
714
- /** Speaker-turn cap. Default for a scripted persona = `2 * turns.length`
715
- * (worker answers each user turn). REQUIRED for a `profile` persona. */
716
- maxTurns?: number;
717
- /** Kickoff message routed to the first speaker (the persona). Default 'Begin.' */
718
- seed?: string;
719
- /** Content-based "until satisfied" halt, called after every turn. `maxTurns` is the
720
- * hard ceiling; this is the early stop (the persona declares the goal met / unreachable). */
721
- haltOn?: HaltPredicate;
722
- signal?: AbortSignal;
723
- /** Worker participant / transcript speaker label. Default 'agent'. */
724
- workerName?: string;
725
- }
726
- interface PersonaConversationResult {
727
- transcript: ConversationTurn[];
728
- turns: number;
729
- halted: HaltReason;
730
- /** Worker-only spend (the side under test). */
731
- costUsd: number;
732
- tokensIn: number;
733
- tokensOut: number;
734
- }
735
- /**
736
- * Run one worker profile against one persona as a multi-round conversation.
737
- * The persona leads (participant 0): it speaks, the worker answers, repeat,
738
- * until `maxTurns`. Returns the persistent transcript + worker-only usage.
739
- */
740
- declare function runPersonaConversation(opts: RunPersonaConversationOptions): Promise<PersonaConversationResult>;
741
- interface RunPersonaConfig<TScenario extends Scenario, TArtifact> {
742
- /** Turn an `AgentProfile` into a runnable backend (router / sandbox / fake). */
743
- backendFor: (profile: AgentProfile, role: 'worker' | 'persona') => AgentExecutionBackend;
744
- /** Render a profile's system prompt. */
745
- systemPromptOf: (profile: AgentProfile) => string;
746
- /** The persona driving each scenario — a driver profile or scripted turns. */
747
- personaOf: (scenario: TScenario) => PersonaDriver;
748
- /** Build the scored artifact from the finished transcript. */
749
- artifactOf: (transcript: ConversationTurn[], scenario: TScenario) => TArtifact;
750
- /** Speaker-turn cap (required when a persona is profile-driven). */
751
- maxTurns?: (scenario: TScenario) => number;
752
- seed?: (scenario: TScenario) => string;
753
- workerName?: string;
754
- }
755
- /**
756
- * Wrap {@link runPersonaConversation} as a `ProfileDispatchFn` for
757
- * `runProfileMatrix`: the profile axis is the worker-under-test, the scenario
758
- * axis is the persona, and the runner is the cell. Meters the worker through
759
- * `ctx.cost` so the matrix's backend-integrity guard sees real usage.
760
- */
761
- declare function runPersonaDispatch<TScenario extends Scenario, TArtifact>(config: RunPersonaConfig<TScenario, TArtifact>): ProfileDispatchFn<TScenario, TArtifact>;
762
-
763
- /**
764
- * `evalPersona` — the one-call user-sim product eval. Run a worker `AgentProfile` (the agent under
765
- * test) against a PERSONA (a simulated user — a scripted script or an LLM driver profile) as a
766
- * multi-round conversation, with the two seams `runPersonaConversation` otherwise makes you hand-wire
767
- * defaulted:
768
- *
769
- * - `backendFor` defaults to `createOpenAICompatibleBackend({ apiKey, baseUrl, model })` (the
770
- * OpenAI-compatible router endpoint) for both the worker and a profile-driven persona;
771
- * - `systemPromptOf` defaults to `p.prompt?.systemPrompt ?? ''`.
772
- *
773
- * Either is overridable (tests pass a fake `backendFor` to run offline). `maxTurns` (the hard
774
- * ceiling) and `haltOn` (the "until satisfied" early stop) pass straight through. Mirrors
775
- * `supervise()`'s defaulting style: the common case is one call; the raw `runPersonaConversation`
776
- * seam stays available for full control.
777
- *
778
- * The profile here is the authored `AgentProfile` (with `prompt.systemPrompt`), which is why the
779
- * default `systemPromptOf` can read it. `runPersonaConversation` treats the profile opaquely — only
780
- * the two callbacks inspect it — so the worker/persona profiles flow straight through.
781
- */
782
-
783
- interface EvalPersonaOptions {
784
- /** Router (or OpenAI-compatible) endpoint for the DEFAULT backend. Required unless `backendFor`
785
- * is supplied (tests/advanced override the backend entirely and may omit these). */
786
- apiKey?: string;
787
- baseUrl?: string;
788
- model?: string;
789
- /** Override the backend seam directly instead of deriving it from `apiKey`/`baseUrl`/`model`
790
- * (the offline-test path: pass a fake here and the credentials are not needed). */
791
- backendFor?: (profile: AgentProfile$1, role: 'worker' | 'persona') => AgentExecutionBackend;
792
- /** Override system-prompt rendering. Default: `p.prompt?.systemPrompt ?? ''`. */
793
- systemPromptOf?: (profile: AgentProfile$1) => string;
794
- /** Hard speaker-turn ceiling. REQUIRED for a profile-driven persona; for a scripted persona it
795
- * defaults to `2 * turns.length`. `maxTurns` is a CEILING, NOT a target — `maxTurns: 0` is zero
796
- * turns, not run-until-done; `haltOn` is the "until satisfied" knob. */
797
- maxTurns?: number;
798
- /** Content-based early stop (the persona declares the goal met / unreachable). */
799
- haltOn?: HaltPredicate;
800
- /** Kickoff message to the persona. Default 'Begin.' */
801
- seed?: string;
802
- signal?: AbortSignal;
803
- /** Worker transcript speaker label. Default 'agent'. */
804
- workerName?: string;
805
- }
806
- /** The persona side, authored against the same `AgentProfile` shape as the worker. */
807
- type EvalPersona = {
808
- kind: 'scripted';
809
- turns: string[];
810
- } | {
811
- kind: 'profile';
812
- profile: AgentProfile$1;
813
- };
814
- declare function evalPersona(worker: AgentProfile$1, persona: EvalPersona, opts?: EvalPersonaOptions): Promise<PersonaConversationResult>;
815
-
816
678
  /**
817
679
  * @stable
818
680
  *
@@ -947,6 +809,91 @@ declare class SqlConversationJournal implements ConversationJournal {
947
809
  declare function runConversation(conversation: Conversation, options: RunConversationOptions): Promise<ConversationResult>;
948
810
  declare function runConversationStream(conversation: Conversation, options: RunConversationOptions): AsyncIterable<ConversationStreamEvent>;
949
811
 
812
+ /**
813
+ * `runPersonaConversation` — the persona loop runner: run a WORKER `AgentProfile`
814
+ * (the agent under test) as a multi-round conversation driven by a PERSONA (the
815
+ * simulated user), over the persistent conversation transcript.
816
+ *
817
+ * It is profiles-vs-profiles: the persona is itself a driver `AgentProfile` (an
818
+ * LLM role-playing the user from its facts) — `runConversation` runs the two
819
+ * against each other. Scripted persona turns are kept as a deterministic
820
+ * fast-path. Only the WORKER is metered (it is the side under test); the
821
+ * persona-driver is the test harness, not billed against the agent.
822
+ *
823
+ * `runPersonaDispatch` wraps the runner as a `ProfileDispatchFn` so it drops
824
+ * straight into `runProfileMatrix({ dispatch })` — the same loop serves a single
825
+ * cell and the whole matrix, replacing the per-agent hand-rolled
826
+ * `dispatchWithSurface` bridges.
827
+ */
828
+
829
+ /** A persona that drives the conversation: either a full driver `AgentProfile`
830
+ * (an LLM user-sim) or a deterministic script of user turns (the fast-path). */
831
+ type PersonaDriver = {
832
+ kind: 'profile';
833
+ profile: AgentProfile;
834
+ } | {
835
+ kind: 'scripted';
836
+ turns: string[];
837
+ };
838
+ interface RunPersonaConversationOptions {
839
+ /** The agent under test. Metered; its rendered prompt leads its turns. */
840
+ worker: AgentProfile;
841
+ /** The simulated user driving the dialogue. */
842
+ persona: PersonaDriver;
843
+ /** Turn an `AgentProfile` into a runnable backend (router / sandbox / fake).
844
+ * Applied to the worker and to a `profile`-kind persona. */
845
+ backendFor: (profile: AgentProfile, role: 'worker' | 'persona') => AgentExecutionBackend;
846
+ /** Render a profile's system prompt — prepended to that profile's messages. */
847
+ systemPromptOf: (profile: AgentProfile) => string;
848
+ /** Speaker-turn cap. Default for a scripted persona = `2 * turns.length`
849
+ * (worker answers each user turn). REQUIRED for a `profile` persona. */
850
+ maxTurns?: number;
851
+ /** Kickoff message routed to the first speaker (the persona). Default 'Begin.' */
852
+ seed?: string;
853
+ /** Content-based "until satisfied" halt, called after every turn. `maxTurns` is the
854
+ * hard ceiling; this is the early stop (the persona declares the goal met / unreachable). */
855
+ haltOn?: HaltPredicate;
856
+ signal?: AbortSignal;
857
+ /** Worker participant / transcript speaker label. Default 'agent'. */
858
+ workerName?: string;
859
+ }
860
+ interface PersonaConversationResult {
861
+ transcript: ConversationTurn[];
862
+ turns: number;
863
+ halted: HaltReason;
864
+ /** Worker-only spend (the side under test). */
865
+ costUsd: number;
866
+ tokensIn: number;
867
+ tokensOut: number;
868
+ }
869
+ /**
870
+ * Run one worker profile against one persona as a multi-round conversation.
871
+ * The persona leads (participant 0): it speaks, the worker answers, repeat,
872
+ * until `maxTurns`. Returns the persistent transcript + worker-only usage.
873
+ */
874
+ declare function runPersonaConversation(opts: RunPersonaConversationOptions): Promise<PersonaConversationResult>;
875
+ interface RunPersonaConfig<TScenario extends Scenario, TArtifact> {
876
+ /** Turn an `AgentProfile` into a runnable backend (router / sandbox / fake). */
877
+ backendFor: (profile: AgentProfile, role: 'worker' | 'persona') => AgentExecutionBackend;
878
+ /** Render a profile's system prompt. */
879
+ systemPromptOf: (profile: AgentProfile) => string;
880
+ /** The persona driving each scenario — a driver profile or scripted turns. */
881
+ personaOf: (scenario: TScenario) => PersonaDriver;
882
+ /** Build the scored artifact from the finished transcript. */
883
+ artifactOf: (transcript: ConversationTurn[], scenario: TScenario) => TArtifact;
884
+ /** Speaker-turn cap (required when a persona is profile-driven). */
885
+ maxTurns?: (scenario: TScenario) => number;
886
+ seed?: (scenario: TScenario) => string;
887
+ workerName?: string;
888
+ }
889
+ /**
890
+ * Wrap {@link runPersonaConversation} as a `ProfileDispatchFn` for
891
+ * `runProfileMatrix`: the profile axis is the worker-under-test, the scenario
892
+ * axis is the persona, and the runner is the cell. Meters the worker through
893
+ * `ctx.cost` so the matrix's backend-integrity guard sees real usage.
894
+ */
895
+ declare function runPersonaDispatch<TScenario extends Scenario, TArtifact>(config: RunPersonaConfig<TScenario, TArtifact>): ProfileDispatchFn<TScenario, TArtifact>;
896
+
950
897
  /**
951
898
  * @stable
952
899
  *
@@ -1735,4 +1682,4 @@ interface StreamToolLoopOptions<Raw> {
1735
1682
  * `capped` if it stops for any non-completed reason with calls still pending. */
1736
1683
  declare function streamToolLoop<Raw>(opts: StreamToolLoopOptions<Raw>): AsyncGenerator<StreamToolLoopYield<Raw>, void, unknown>;
1737
1684
 
1738
- export { AgentBackendContext, AgentBackendInput, AgentExecutionBackend, AgentRuntimeEvent, AgentTaskRunResult, AgentTaskStatus, type AuthSource, type BackendCallPolicy, BackendTransportError, CandidateGenerator, type ChatStreamEvent, type ChatTurnHooks, type ChatTurnIdentity, type ChatTurnProducer, type ChatTurnResult, type CircuitBreakerConfig, CircuitBreakerState, CircuitOpenError, type Conversation, type ConversationDriveState, type ConversationJournal, type ConversationJournalEntry, type ConversationParticipant, type ConversationPolicy, type ConversationResult, type ConversationStreamEvent, type ConversationTurn, type D1DatabaseLike, type D1StmtLike, DEFAULT_MAX_DEPTH, DEFAULT_ROUTER_BASE_URL, DeadlineExceededError, type EvalPersonaOptions, FORWARD_HEADERS, FileConversationJournal, type ForwardHeaderName, type HaltContext, type HaltPredicate, type HaltReason, type HaltSignal, type ImproveOptions, type ImproveResult, type ImproveSurface, InMemoryConversationJournal, InMemoryRuntimeSessionStore, type ModelInfo, OpenAIChatResponseFormat, OpenAIChatTool, OpenAIChatToolChoice, type PersonaConversationResult, type PersonaDriver, PlannerError, type PropagatedHeaders, type ReflectiveGeneratorOptions, type ResolvedChatModel, type RetryBackoff, type RetryableErrorPredicate, type RouterEnv, type RunChatTurnInput, type RunConversationOptions, type RunPersonaConfig, type RunPersonaConversationOptions, type RunToolLoopOptions, type RuntimeEventCollector, RuntimeHooks, RuntimeRunStateError, RuntimeSessionStore, RuntimeStreamEvent, type RuntimeStreamEventCollector, type RuntimeTelemetryOptions, type SanitizedKnowledgeReadinessReport, type SqlAdapter, SqlConversationJournal, type StreamToolLoopOptions, type StreamToolLoopYield, type ToolCallOutcome, type ToolLoopAssistantToolCall, type ToolLoopCall, type ToolLoopEvent, type ToolLoopMessage, type ToolLoopResult, type ToolLoopStopReason, type TurnOrder, applyRunRecordDefaults, buildForwardHeaders, cleanModelId, computeBackoff, createConversationBackend, createIterableBackend, createOpenAICompatibleBackend, createRuntimeEventCollector, createRuntimeStreamEventCollector, createSandboxPromptBackend, d1ToSqlAdapter, decideKnowledgeReadiness, defaultIsRetryable, defineConversation, deriveExecutionId, evalPersona, getModels, handleChatTurn, improve, isDepthExceeded, makePerAttemptSignal, mcpBuildPrompt, readDepth, readinessServerSentEvent, reflectiveGenerator, resolveChatModel, resolveRouterBaseUrl, runAgentTask, runAgentTaskStream, runConversation, runConversationStream, runPersonaConversation, runPersonaDispatch, runToolLoop, runtimeStreamServerSentEvent, sanitizeAgentRuntimeEvent, sanitizeKnowledgeReadinessReport, sanitizeRuntimeStreamEvent, sleep, slugifySpeaker, streamToolLoop, toolBuildPrompt, turnId, validateChatModelId };
1685
+ export { AgentBackendContext, AgentBackendInput, AgentExecutionBackend, AgentRuntimeEvent, AgentTaskRunResult, AgentTaskStatus, type AuthSource, type BackendCallPolicy, BackendTransportError, CandidateGenerator, type ChatStreamEvent, type ChatTurnHooks, type ChatTurnIdentity, type ChatTurnProducer, type ChatTurnResult, type CircuitBreakerConfig, CircuitBreakerState, CircuitOpenError, type Conversation, type ConversationDriveState, type ConversationJournal, type ConversationJournalEntry, type ConversationParticipant, type ConversationPolicy, type ConversationResult, type ConversationStreamEvent, type ConversationTurn, type D1DatabaseLike, type D1StmtLike, DEFAULT_MAX_DEPTH, DEFAULT_ROUTER_BASE_URL, DeadlineExceededError, FORWARD_HEADERS, FileConversationJournal, type ForwardHeaderName, type HaltContext, type HaltPredicate, type HaltReason, type HaltSignal, type ImproveOptions, type ImproveResult, type ImproveSurface, InMemoryConversationJournal, InMemoryRuntimeSessionStore, type ModelInfo, OpenAIChatResponseFormat, OpenAIChatTool, OpenAIChatToolChoice, type PersonaConversationResult, type PersonaDriver, PlannerError, type PropagatedHeaders, type ReflectiveGeneratorOptions, type ResolvedChatModel, type RetryBackoff, type RetryableErrorPredicate, type RouterEnv, type RunChatTurnInput, type RunConversationOptions, type RunPersonaConfig, type RunPersonaConversationOptions, type RunToolLoopOptions, type RuntimeEventCollector, RuntimeHooks, RuntimeRunStateError, RuntimeSessionStore, RuntimeStreamEvent, type RuntimeStreamEventCollector, type RuntimeTelemetryOptions, type SanitizedKnowledgeReadinessReport, type SqlAdapter, SqlConversationJournal, type StreamToolLoopOptions, type StreamToolLoopYield, type ToolCallOutcome, type ToolLoopAssistantToolCall, type ToolLoopCall, type ToolLoopEvent, type ToolLoopMessage, type ToolLoopResult, type ToolLoopStopReason, type TurnOrder, applyRunRecordDefaults, buildForwardHeaders, cleanModelId, computeBackoff, createConversationBackend, createIterableBackend, createOpenAICompatibleBackend, createRuntimeEventCollector, createRuntimeStreamEventCollector, createSandboxPromptBackend, d1ToSqlAdapter, decideKnowledgeReadiness, defaultIsRetryable, defineConversation, deriveExecutionId, getModels, handleChatTurn, improve, isDepthExceeded, makePerAttemptSignal, mcpBuildPrompt, readDepth, readinessServerSentEvent, reflectiveGenerator, resolveChatModel, resolveRouterBaseUrl, runAgentTask, runAgentTaskStream, runConversation, runConversationStream, runPersonaConversation, runPersonaDispatch, runToolLoop, runtimeStreamServerSentEvent, sanitizeAgentRuntimeEvent, sanitizeKnowledgeReadinessReport, sanitizeRuntimeStreamEvent, sleep, slugifySpeaker, streamToolLoop, toolBuildPrompt, turnId, validateChatModelId };
package/dist/index.js CHANGED
@@ -1430,146 +1430,6 @@ function normalizePolicy(policy, participantCount) {
1430
1430
  return { ...policy, turnOrder };
1431
1431
  }
1432
1432
 
1433
- // src/conversation/run-persona.ts
1434
- function withProfilePrompt(inner, systemPrompt, counter) {
1435
- return {
1436
- kind: inner.kind,
1437
- start: inner.start ? (input, ctx) => inner.start(input, ctx) : void 0,
1438
- resume: inner.resume ? (session, input, ctx) => inner.resume(session, input, ctx) : void 0,
1439
- stop: inner.stop ? (session, reason) => inner.stop(session, reason) : void 0,
1440
- async *stream(input, context) {
1441
- const base = input.messages ?? (input.message ? [{ role: "user", content: input.message }] : []);
1442
- const messages = base[0]?.role === "system" ? base : [{ role: "system", content: systemPrompt }, ...base];
1443
- for await (const event of inner.stream({ ...input, messages }, context)) {
1444
- if (counter && event.type === "llm_call") {
1445
- counter.tokensIn += event.tokensIn ?? 0;
1446
- counter.tokensOut += event.tokensOut ?? 0;
1447
- counter.costUsd += event.costUsd ?? 0;
1448
- }
1449
- yield event;
1450
- }
1451
- }
1452
- };
1453
- }
1454
- function scriptedPersonaBackend(turns) {
1455
- let idx = 0;
1456
- return createIterableBackend({
1457
- kind: "persona-user",
1458
- async *stream(_input, context) {
1459
- const text = turns[idx];
1460
- if (text === void 0) {
1461
- throw new Error(
1462
- `persona-user: ran out of scripted turns at index ${idx} (had ${turns.length})`
1463
- );
1464
- }
1465
- idx += 1;
1466
- yield {
1467
- type: "text_delta",
1468
- task: context.task,
1469
- session: context.session,
1470
- text,
1471
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1472
- };
1473
- }
1474
- });
1475
- }
1476
- async function runPersonaConversation(opts) {
1477
- const counter = { tokensIn: 0, tokensOut: 0, costUsd: 0 };
1478
- const workerName = opts.workerName ?? "agent";
1479
- const worker = withProfilePrompt(
1480
- opts.backendFor(opts.worker, "worker"),
1481
- opts.systemPromptOf(opts.worker),
1482
- counter
1483
- );
1484
- let persona;
1485
- let maxTurns;
1486
- if (opts.persona.kind === "scripted") {
1487
- if (opts.persona.turns.length === 0) {
1488
- throw new Error("runPersonaConversation: scripted persona has no turns");
1489
- }
1490
- persona = scriptedPersonaBackend(opts.persona.turns);
1491
- maxTurns = opts.maxTurns ?? 2 * opts.persona.turns.length;
1492
- } else {
1493
- persona = withProfilePrompt(
1494
- opts.backendFor(opts.persona.profile, "persona"),
1495
- opts.systemPromptOf(opts.persona.profile)
1496
- );
1497
- if (opts.maxTurns === void 0) {
1498
- throw new Error("runPersonaConversation: maxTurns is required for a profile-driven persona");
1499
- }
1500
- maxTurns = opts.maxTurns;
1501
- }
1502
- const conversation = defineConversation({
1503
- // Persona leads (participant 0): the seed routes to it, it produces the
1504
- // user turn, the worker answers, alternate.
1505
- participants: [
1506
- { name: "user", backend: persona },
1507
- { name: workerName, backend: worker }
1508
- ],
1509
- policy: { maxTurns, turnOrder: "alternate", ...opts.haltOn ? { haltOn: opts.haltOn } : {} }
1510
- });
1511
- const result = await runConversation(conversation, {
1512
- seed: opts.seed ?? "Begin.",
1513
- signal: opts.signal
1514
- });
1515
- const costUsd = counter.costUsd > 0 ? counter.costUsd : opts.persona.kind === "scripted" ? result.spentCreditsCents / 100 : 0;
1516
- return {
1517
- transcript: result.transcript,
1518
- turns: result.turns,
1519
- halted: result.halted,
1520
- costUsd,
1521
- tokensIn: counter.tokensIn,
1522
- tokensOut: counter.tokensOut
1523
- };
1524
- }
1525
- function runPersonaDispatch(config) {
1526
- return async (worker, scenario, ctx) => {
1527
- const result = await runPersonaConversation({
1528
- worker,
1529
- persona: config.personaOf(scenario),
1530
- backendFor: config.backendFor,
1531
- systemPromptOf: config.systemPromptOf,
1532
- maxTurns: config.maxTurns?.(scenario),
1533
- seed: config.seed?.(scenario),
1534
- signal: ctx.signal,
1535
- workerName: config.workerName
1536
- });
1537
- ctx.cost.observe(result.costUsd, "persona-conversation");
1538
- ctx.cost.observeTokens({ input: result.tokensIn, output: result.tokensOut });
1539
- return config.artifactOf(result.transcript, scenario);
1540
- };
1541
- }
1542
-
1543
- // src/conversation/eval-persona.ts
1544
- function evalPersona(worker, persona, opts = {}) {
1545
- const defaultBackendFor = () => {
1546
- if (!opts.apiKey || !opts.baseUrl || !opts.model) {
1547
- throw new Error(
1548
- "evalPersona: provide opts.{apiKey,baseUrl,model} for the default backend, or opts.backendFor"
1549
- );
1550
- }
1551
- const { apiKey, baseUrl, model } = opts;
1552
- return () => createOpenAICompatibleBackend({ apiKey, baseUrl, model });
1553
- };
1554
- const backendFor = opts.backendFor ?? defaultBackendFor();
1555
- const systemPromptOf = opts.systemPromptOf ?? ((p) => p.prompt?.systemPrompt ?? "");
1556
- return runPersonaConversation({
1557
- // runPersonaConversation types its profile as the benchmark-cell AgentProfile; here it is the
1558
- // authored AgentProfile (the carrier of prompt.systemPrompt). The runner never inspects the
1559
- // profile itself — only backendFor/systemPromptOf do, and both are typed for THIS profile — so
1560
- // the cast at this single boundary is sound.
1561
- worker,
1562
- persona,
1563
- backendFor,
1564
- systemPromptOf,
1565
- ...opts.maxTurns !== void 0 ? { maxTurns: opts.maxTurns } : {},
1566
- ...opts.haltOn ? { haltOn: opts.haltOn } : {},
1567
- ...opts.seed !== void 0 ? { seed: opts.seed } : {},
1568
- ...opts.signal ? { signal: opts.signal } : {},
1569
- ...opts.workerName !== void 0 ? { workerName: opts.workerName } : {}
1570
- });
1571
- }
1572
-
1573
1433
  // src/conversation/journal.ts
1574
1434
  var InMemoryConversationJournal = class {
1575
1435
  entries = /* @__PURE__ */ new Map();
@@ -1823,6 +1683,116 @@ var SqlConversationJournal = class {
1823
1683
  }
1824
1684
  };
1825
1685
 
1686
+ // src/conversation/run-persona.ts
1687
+ function withProfilePrompt(inner, systemPrompt, counter) {
1688
+ return {
1689
+ kind: inner.kind,
1690
+ start: inner.start ? (input, ctx) => inner.start(input, ctx) : void 0,
1691
+ resume: inner.resume ? (session, input, ctx) => inner.resume(session, input, ctx) : void 0,
1692
+ stop: inner.stop ? (session, reason) => inner.stop(session, reason) : void 0,
1693
+ async *stream(input, context) {
1694
+ const base = input.messages ?? (input.message ? [{ role: "user", content: input.message }] : []);
1695
+ const messages = base[0]?.role === "system" ? base : [{ role: "system", content: systemPrompt }, ...base];
1696
+ for await (const event of inner.stream({ ...input, messages }, context)) {
1697
+ if (counter && event.type === "llm_call") {
1698
+ counter.tokensIn += event.tokensIn ?? 0;
1699
+ counter.tokensOut += event.tokensOut ?? 0;
1700
+ counter.costUsd += event.costUsd ?? 0;
1701
+ }
1702
+ yield event;
1703
+ }
1704
+ }
1705
+ };
1706
+ }
1707
+ function scriptedPersonaBackend(turns) {
1708
+ let idx = 0;
1709
+ return createIterableBackend({
1710
+ kind: "persona-user",
1711
+ async *stream(_input, context) {
1712
+ const text = turns[idx];
1713
+ if (text === void 0) {
1714
+ throw new Error(
1715
+ `persona-user: ran out of scripted turns at index ${idx} (had ${turns.length})`
1716
+ );
1717
+ }
1718
+ idx += 1;
1719
+ yield {
1720
+ type: "text_delta",
1721
+ task: context.task,
1722
+ session: context.session,
1723
+ text,
1724
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1725
+ };
1726
+ }
1727
+ });
1728
+ }
1729
+ async function runPersonaConversation(opts) {
1730
+ const counter = { tokensIn: 0, tokensOut: 0, costUsd: 0 };
1731
+ const workerName = opts.workerName ?? "agent";
1732
+ const worker = withProfilePrompt(
1733
+ opts.backendFor(opts.worker, "worker"),
1734
+ opts.systemPromptOf(opts.worker),
1735
+ counter
1736
+ );
1737
+ let persona;
1738
+ let maxTurns;
1739
+ if (opts.persona.kind === "scripted") {
1740
+ if (opts.persona.turns.length === 0) {
1741
+ throw new Error("runPersonaConversation: scripted persona has no turns");
1742
+ }
1743
+ persona = scriptedPersonaBackend(opts.persona.turns);
1744
+ maxTurns = opts.maxTurns ?? 2 * opts.persona.turns.length;
1745
+ } else {
1746
+ persona = withProfilePrompt(
1747
+ opts.backendFor(opts.persona.profile, "persona"),
1748
+ opts.systemPromptOf(opts.persona.profile)
1749
+ );
1750
+ if (opts.maxTurns === void 0) {
1751
+ throw new Error("runPersonaConversation: maxTurns is required for a profile-driven persona");
1752
+ }
1753
+ maxTurns = opts.maxTurns;
1754
+ }
1755
+ const conversation = defineConversation({
1756
+ // Persona leads (participant 0): the seed routes to it, it produces the
1757
+ // user turn, the worker answers, alternate.
1758
+ participants: [
1759
+ { name: "user", backend: persona },
1760
+ { name: workerName, backend: worker }
1761
+ ],
1762
+ policy: { maxTurns, turnOrder: "alternate", ...opts.haltOn ? { haltOn: opts.haltOn } : {} }
1763
+ });
1764
+ const result = await runConversation(conversation, {
1765
+ seed: opts.seed ?? "Begin.",
1766
+ signal: opts.signal
1767
+ });
1768
+ const costUsd = counter.costUsd > 0 ? counter.costUsd : opts.persona.kind === "scripted" ? result.spentCreditsCents / 100 : 0;
1769
+ return {
1770
+ transcript: result.transcript,
1771
+ turns: result.turns,
1772
+ halted: result.halted,
1773
+ costUsd,
1774
+ tokensIn: counter.tokensIn,
1775
+ tokensOut: counter.tokensOut
1776
+ };
1777
+ }
1778
+ function runPersonaDispatch(config) {
1779
+ return async (worker, scenario, ctx) => {
1780
+ const result = await runPersonaConversation({
1781
+ worker,
1782
+ persona: config.personaOf(scenario),
1783
+ backendFor: config.backendFor,
1784
+ systemPromptOf: config.systemPromptOf,
1785
+ maxTurns: config.maxTurns?.(scenario),
1786
+ seed: config.seed?.(scenario),
1787
+ signal: ctx.signal,
1788
+ workerName: config.workerName
1789
+ });
1790
+ ctx.cost.observe(result.costUsd, "persona-conversation");
1791
+ ctx.cost.observeTokens({ input: result.tokensIn, output: result.tokensOut });
1792
+ return config.artifactOf(result.transcript, scenario);
1793
+ };
1794
+ }
1795
+
1826
1796
  // src/durable/chat-engine.ts
1827
1797
  var encoder = new TextEncoder();
1828
1798
  function encodeLine(event) {
@@ -3521,7 +3491,6 @@ export {
3521
3491
  defineConversation,
3522
3492
  defineRuntimeHooks,
3523
3493
  deriveExecutionId,
3524
- evalPersona,
3525
3494
  exportEvalRuns,
3526
3495
  getModels,
3527
3496
  handleChatTurn,