@sema-agent/core 5.13.0 → 5.14.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/CHANGELOG.md +296 -0
- package/dist/agents/send-message-tool.js +1 -0
- package/dist/agents/subagent.d.ts +4 -0
- package/dist/agents/subagent.js +133 -41
- package/dist/brain/anthropic.js +33 -10
- package/dist/brain/context-overflow.d.ts +20 -0
- package/dist/brain/context-overflow.js +58 -0
- package/dist/brain/open-responses.js +24 -10
- package/dist/brain/openai.js +29 -11
- package/dist/brain/request-params.d.ts +2 -0
- package/dist/brain/request-params.js +16 -0
- package/dist/brain/stream-engine.d.ts +9 -1
- package/dist/brain/stream-engine.js +256 -27
- package/dist/brain/timeout.d.ts +1 -0
- package/dist/brain/timeout.js +1 -0
- package/dist/core/a2a.d.ts +2 -2
- package/dist/core/a2a.js +3 -3
- package/dist/core/ask-question.d.ts +47 -2
- package/dist/core/ask-question.js +209 -28
- package/dist/core/background-agent-store.d.ts +2 -0
- package/dist/core/checkpoint-store.d.ts +41 -17
- package/dist/core/checkpoint-store.js +114 -3
- package/dist/core/hooks.d.ts +24 -2
- package/dist/core/hooks.js +97 -10
- package/dist/core/human-input-projection.d.ts +12 -0
- package/dist/core/human-input-projection.js +27 -0
- package/dist/core/mcp.d.ts +7 -2
- package/dist/core/mcp.js +7 -7
- package/dist/core/memory-admission.d.ts +4 -0
- package/dist/core/memory-admission.js +3 -0
- package/dist/core/runner/assemble-result.d.ts +1 -0
- package/dist/core/runner/assemble-result.js +1 -1
- package/dist/core/runner/prepare-task.d.ts +16 -6
- package/dist/core/runner/prepare-task.js +301 -24
- package/dist/core/runner/runtask.d.ts +3 -6
- package/dist/core/runner/runtask.js +186 -36
- package/dist/core/runner/tool-output-projection.js +1 -0
- package/dist/core/session-store.d.ts +3 -0
- package/dist/core/session-store.js +4 -0
- package/dist/core/session.d.ts +1 -0
- package/dist/core/store-contracts/background-agent-store-contract.js +19 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +62 -3
- package/dist/core/task-notification.d.ts +2 -0
- package/dist/core/task-notification.js +5 -3
- package/dist/core/task-registry-agent.d.ts +1 -0
- package/dist/core/task-registry-agent.js +6 -0
- package/dist/core/task-registry.d.ts +1 -0
- package/dist/core/task-registry.js +4 -1
- package/dist/core/tool-policy.d.ts +5 -0
- package/dist/core/tool-policy.js +2 -1
- package/dist/core/types.d.ts +32 -1
- package/dist/core/wiring-manifest.d.ts +97 -0
- package/dist/core/wiring-manifest.js +186 -0
- package/dist/engine/compaction/compaction.js +2 -2
- package/dist/engine/harness/agent-harness.d.ts +2 -1
- package/dist/engine/harness/agent-harness.js +8 -1
- package/dist/engine/harness/types.d.ts +3 -1
- package/dist/engine/llm/types.d.ts +7 -0
- package/dist/engine/llm/types.js +8 -1
- package/dist/engine/session/import-validate.d.ts +6 -1
- package/dist/engine/session/import-validate.js +29 -6
- package/dist/engine/session/memory-repo.d.ts +3 -1
- package/dist/engine/session/memory-repo.js +2 -2
- package/dist/index.d.ts +7 -4
- package/dist/index.js +7 -4
- package/dist/internal/harness-types.d.ts +1 -1
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/run-workflow-tool.d.ts +4 -0
- package/dist/orchestration/run-workflow-tool.js +3 -0
- package/dist/orchestration/workflow-types.d.ts +8 -0
- package/dist/orchestration/workflow-types.js +14 -0
- package/dist/orchestration/workflow.d.ts +4 -0
- package/dist/orchestration/workflow.js +134 -5
- package/dist/prompts/default.js +1 -1
- package/dist/stores/file/checkpoint-store.d.ts +3 -5
- package/dist/stores/file/checkpoint-store.js +31 -2
- package/dist/stores/file/index.js +1 -1
- package/dist/stores/file/session-store.d.ts +3 -1
- package/dist/stores/file/session-store.js +2 -2
- package/dist/stores/file/shared-ledger.js +8 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -0
- package/dist/tools/fs/bash-readonly-classifier.js +94 -0
- package/dist/tools/fs/fs-bash.js +31 -12
- package/dist/tools/fs/safety.js +34 -10
- package/package.json +1 -1
|
@@ -38,10 +38,10 @@ export function taskNotificationDedupKey(n) {
|
|
|
38
38
|
export function taskNotificationLaneKey(n) {
|
|
39
39
|
return n.task_type === "external" ? `external:${n.task_id}` : n.task_id;
|
|
40
40
|
}
|
|
41
|
-
function attrEscape(value) {
|
|
41
|
+
export function attrEscape(value) {
|
|
42
42
|
return value.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
43
43
|
}
|
|
44
|
-
const EXTERNAL_SOURCE_MAX = 120;
|
|
44
|
+
export const EXTERNAL_SOURCE_MAX = 120;
|
|
45
45
|
export function renderTaskNotificationXml(n) {
|
|
46
46
|
const usage = n.usage === undefined
|
|
47
47
|
? undefined
|
|
@@ -54,7 +54,9 @@ export function renderTaskNotificationXml(n) {
|
|
|
54
54
|
}
|
|
55
55
|
})();
|
|
56
56
|
const open = n.task_type === "external"
|
|
57
|
-
? `<task-notification type="external"${n.source !== undefined
|
|
57
|
+
? `<task-notification type="external"${n.source !== undefined
|
|
58
|
+
? ` from="${attrEscape(inlineUntrusted(n.source, EXTERNAL_SOURCE_MAX))}" from-unverified="true"`
|
|
59
|
+
: ""}>`
|
|
58
60
|
: "<task-notification>";
|
|
59
61
|
return [
|
|
60
62
|
open,
|
|
@@ -28,6 +28,7 @@ export declare function reapDurableAgentsLane(core: DurableAgentCore, scope: str
|
|
|
28
28
|
}>;
|
|
29
29
|
export declare function releaseDurableTranscriptAnchorLane(core: DurableAgentCore, id: string): void;
|
|
30
30
|
export declare function bindBackgroundAgentSessionLane(core: DurableAgentCore, id: string, sessionId: string): void;
|
|
31
|
+
export declare function recordBackgroundAgentOrgAdmissionLane(core: DurableAgentCore, id: string, verdict: import("./memory-admission.js").OwnOrgAdmissionVerdict): void;
|
|
31
32
|
export declare function registerBackgroundAgentLane(core: DurableAgentCore, input: RegisterBackgroundAgentInput): string;
|
|
32
33
|
export declare function parkBackgroundAgentLane(core: DurableAgentCore, id: string, park: {
|
|
33
34
|
checkpointToken: string;
|
|
@@ -247,6 +247,12 @@ export function bindBackgroundAgentSessionLane(core, id, sessionId) {
|
|
|
247
247
|
handle.sessionId = sessionId;
|
|
248
248
|
durableAgentWriteLane(handle, { sessionId });
|
|
249
249
|
}
|
|
250
|
+
export function recordBackgroundAgentOrgAdmissionLane(core, id, verdict) {
|
|
251
|
+
const handle = core.handles.get(id);
|
|
252
|
+
if (!handle || handle.type !== "background_agent")
|
|
253
|
+
return;
|
|
254
|
+
durableAgentWriteLane(handle, { admittedOrgScopes: [...verdict.scopes], admittedOrgWriteScope: verdict.writeScope });
|
|
255
|
+
}
|
|
250
256
|
export function registerBackgroundAgentLane(core, input) {
|
|
251
257
|
assertOwnership(input, "registerBackgroundAgent");
|
|
252
258
|
if (input.id !== undefined && !DURABLE_AGENT_HANDLE_RE.test(input.id)) {
|
|
@@ -101,6 +101,7 @@ export declare class TaskRegistry {
|
|
|
101
101
|
releaseDurableTranscriptAnchor(id: string): void;
|
|
102
102
|
bindBackgroundAgentSession(id: string, sessionId: string): void;
|
|
103
103
|
registerBackgroundAgent(input: RegisterBackgroundAgentInput): string;
|
|
104
|
+
recordBackgroundAgentOrgAdmission(id: string, verdict: import("./memory-admission.js").OwnOrgAdmissionVerdict): void;
|
|
104
105
|
parkBackgroundAgent(id: string, park: {
|
|
105
106
|
checkpointToken: string;
|
|
106
107
|
seq?: number;
|
|
@@ -10,7 +10,7 @@ import { registerWorkflowLane, pollWorkflowLane, stopWorkflowLane } from "./task
|
|
|
10
10
|
import { mintCompletionId, canAccessWorkflowRun, formatWorkflowRun, clipTaskOutput, assertOwnership, sleepPollStep, statusFromBackground, rollSpoolText, accountDroppedBytes, renderSpoolBody, spoolDropNote, droppedGapNote, alreadyTerminalStopNote, terminalTaskSummary, TASK_OUTPUT_MAX_CHARS, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE, canAccess, DURABLE_AGENT_HANDLE_RE, } from "./task-registry-shared.js";
|
|
11
11
|
export { normalizeAgentName, DURABLE_AGENT_HEARTBEAT_MS, DURABLE_AGENT_HANDLE_RE, BG_AGENT_REAP_STOP_ERROR } from "./task-registry-shared.js";
|
|
12
12
|
import { TASK_OUTPUT_TOOL_NAME, TASK_STOP_TOOL_NAME, TASK_OUTPUT_CONTRACT, TASK_STOP_CONTRACT, TASK_OUTPUT_MISSING_ID_MESSAGE, TASK_STOP_MISSING_ID_MESSAGE, TASK_STOP_PARAMS, resolveTaskIdArg, REGISTRY_TASK_TOOL_CAPS, composeTaskOutputDescription, composeTaskOutputParams, composeTaskStopDescription, } from "./task-tool-shape.js";
|
|
13
|
-
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
13
|
+
import { durableAgentArmedLane, durableAgentRowProbeLane, beginDurableClaimLane, endDurableClaimLane, reapDurableAgentsLane, noteBackgroundAgentActivityLane, reapStaleSessionBackgroundAgentsLane, releaseDurableTranscriptAnchorLane, bindBackgroundAgentSessionLane, registerBackgroundAgentLane, recordBackgroundAgentOrgAdmissionLane, parkBackgroundAgentLane, reconcileParkedAgentsLane, claimParkedAgentLane, rollbackParkedClaimLane, consumeParkedFlipLane, finalizeParkedResumeLane, settleBackgroundAgentLane, abortBackgroundAgentsForOwnerLane, serveDurableAgentRowLane, resolveBackgroundAgentByNameLane, markRetainedContinuationLane, reviveBackgroundAgentLane, settleRevivedAgentLane, unmarkRetainedContinuationLane, attachAgentNotifyLane, deliverToRunningAgentLane, runningBackgroundAgentLabelsLane, runningAgentFooterLane, notFoundRunningAgentsTail, pollBackgroundAgentLane, stopBackgroundAgentLane, } from "./task-registry-agent.js";
|
|
14
14
|
export { canAccessWorkflowRun, clipTaskOutput, MONITOR_BATCH_WINDOW_MS, MONITOR_DEFAULT_TIMEOUT_MS, MONITOR_MAX_TIMEOUT_MS, MONITOR_MAX_BATCHES_PER_MINUTE };
|
|
15
15
|
const BLOCK_DEFAULT_TIMEOUT_MS = 30_000;
|
|
16
16
|
const BLOCK_MAX_TIMEOUT_MS = 600_000;
|
|
@@ -146,6 +146,9 @@ export class TaskRegistry {
|
|
|
146
146
|
registerBackgroundAgent(input) {
|
|
147
147
|
return registerBackgroundAgentLane(this.core, input);
|
|
148
148
|
}
|
|
149
|
+
recordBackgroundAgentOrgAdmission(id, verdict) {
|
|
150
|
+
return recordBackgroundAgentOrgAdmissionLane(this.core, id, verdict);
|
|
151
|
+
}
|
|
149
152
|
parkBackgroundAgent(id, park) {
|
|
150
153
|
return parkBackgroundAgentLane(this.core, id, park);
|
|
151
154
|
}
|
|
@@ -80,12 +80,17 @@ export interface AskRequest {
|
|
|
80
80
|
toolCallId: string;
|
|
81
81
|
args: unknown;
|
|
82
82
|
readonly preview?: unknown;
|
|
83
|
+
readonly boundInputHash?: string;
|
|
83
84
|
message: string;
|
|
84
85
|
readonly principal?: string;
|
|
85
86
|
readonly sourceTaskId?: string;
|
|
86
87
|
readonly fromSubagent?: true;
|
|
87
88
|
readonly sourceAgentName?: string;
|
|
88
89
|
readonly requiresRealApproval?: boolean;
|
|
90
|
+
readonly riskAxes?: {
|
|
91
|
+
readonly irreversible?: boolean;
|
|
92
|
+
readonly egress?: boolean;
|
|
93
|
+
};
|
|
89
94
|
readonly delegation?: AskDelegationProvenance;
|
|
90
95
|
}
|
|
91
96
|
export type OnAsk = "deny" | "allow" | ((req: AskRequest, signal?: AbortSignal) => AskOutcome | Promise<AskOutcome>);
|
package/dist/core/tool-policy.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { isAbsolute, join, normalize as normalizePath, sep } from "node:path";
|
|
3
3
|
import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
|
|
4
|
+
import { boundInputHashOf } from "./canonical-json.js";
|
|
4
5
|
import { writeTargetPath } from "../tools/fs/safety.js";
|
|
5
6
|
export function decisionText(d) {
|
|
6
7
|
return d.message;
|
|
@@ -606,7 +607,7 @@ export async function resolveAsk(req, onAsk, signal) {
|
|
|
606
607
|
decisionReason: "mode",
|
|
607
608
|
};
|
|
608
609
|
}
|
|
609
|
-
ok = await onAsk({ ...req, args: approverView.value }, signal);
|
|
610
|
+
ok = await onAsk({ ...req, boundInputHash: boundInputHashOf(presented.value), args: approverView.value }, signal);
|
|
610
611
|
}
|
|
611
612
|
catch (err) {
|
|
612
613
|
return {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { TSchema } from "typebox";
|
|
2
2
|
import type { AgentTool, ThinkingLevel } from "../internal/harness.js";
|
|
3
|
-
import type { CompleteSimpleFn, DocumentContent, ImageContent, Model, ResilienceOptions, StreamFn, TextContent } from "../internal/llm.js";
|
|
3
|
+
import type { ActorAssertion, CompleteSimpleFn, DocumentContent, ImageContent, Model, ResilienceOptions, StreamFn, TextContent } from "../internal/llm.js";
|
|
4
4
|
import type { TaskNotificationPayload } from "./task-notification.js";
|
|
5
5
|
export type ModelRef = string | Model;
|
|
6
6
|
export interface StaleToolResultOffloadOptions {
|
|
@@ -129,6 +129,7 @@ export interface ToolExecuteContext {
|
|
|
129
129
|
taskId?: string;
|
|
130
130
|
sessionId?: string;
|
|
131
131
|
backgroundScope?: "task" | "session";
|
|
132
|
+
interactionPosture?: "interactive" | "headless";
|
|
132
133
|
onBackgroundChildEvent?: (event: BackgroundChildEvent) => void;
|
|
133
134
|
onTaskNotification?: (n: import("./task-notification.js").TaskNotificationPayload, opts?: {
|
|
134
135
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
@@ -274,6 +275,9 @@ export interface TaskSpec {
|
|
|
274
275
|
taskId?: string;
|
|
275
276
|
objective: string;
|
|
276
277
|
principal?: string;
|
|
278
|
+
actor?: ActorAssertion;
|
|
279
|
+
interactionPosture?: "interactive" | "headless";
|
|
280
|
+
interactiveQuestionFallback?: boolean;
|
|
277
281
|
images?: ImageInput[];
|
|
278
282
|
sessionId?: string;
|
|
279
283
|
requireExistingSession?: boolean;
|
|
@@ -436,6 +440,10 @@ export interface TaskResult {
|
|
|
436
440
|
code: "conversation_only" | "files_env_unsupported" | "snapshot_store_unconfigured";
|
|
437
441
|
message: string;
|
|
438
442
|
}>;
|
|
443
|
+
strandedHumanAnswers?: ReadonlyArray<{
|
|
444
|
+
deliveryId: string;
|
|
445
|
+
toolCallId: string;
|
|
446
|
+
}>;
|
|
439
447
|
stats: {
|
|
440
448
|
turns: number;
|
|
441
449
|
tokens: number;
|
|
@@ -517,6 +525,9 @@ export interface ToolActivity {
|
|
|
517
525
|
arg?: string;
|
|
518
526
|
isError?: boolean;
|
|
519
527
|
}
|
|
528
|
+
export type HumanInputSource = "objective" | "steer" | "next_turn" | "wake" | "external" | "system";
|
|
529
|
+
export type HumanInputDelivery = "applied" | "queued" | "parked_for_wake";
|
|
530
|
+
export type DelegationTaskType = Extract<TaskNotificationPayload["task_type"], "background_agent" | "workflow">;
|
|
520
531
|
export type TaskEvent = ({
|
|
521
532
|
type: "text_delta";
|
|
522
533
|
delta: string;
|
|
@@ -613,6 +624,17 @@ export type TaskEvent = ({
|
|
|
613
624
|
entryId: string;
|
|
614
625
|
role: "user" | "assistant" | "toolResult";
|
|
615
626
|
toolCallId?: string;
|
|
627
|
+
} & TaskEventIdentity) | ({
|
|
628
|
+
type: "human_input";
|
|
629
|
+
inputId: string;
|
|
630
|
+
sessionSeq: number;
|
|
631
|
+
carrier: string;
|
|
632
|
+
source: HumanInputSource;
|
|
633
|
+
issuer?: string;
|
|
634
|
+
actor?: ActorAssertion;
|
|
635
|
+
delivery: HumanInputDelivery;
|
|
636
|
+
principal?: string;
|
|
637
|
+
entryId?: string;
|
|
616
638
|
} & TaskEventIdentity) | ({
|
|
617
639
|
type: "status";
|
|
618
640
|
} & BrainStatus & TaskEventIdentity) | ({
|
|
@@ -621,6 +643,7 @@ export type TaskEvent = ({
|
|
|
621
643
|
} & TaskEventIdentity) | ({
|
|
622
644
|
type: "task_progress";
|
|
623
645
|
taskId: string;
|
|
646
|
+
taskType?: DelegationTaskType;
|
|
624
647
|
workflowRunId?: string;
|
|
625
648
|
workflowAgentLabel?: string;
|
|
626
649
|
parentTaskId?: string;
|
|
@@ -635,16 +658,23 @@ export type TaskEvent = ({
|
|
|
635
658
|
} & TaskEventIdentity) | ({
|
|
636
659
|
type: "workspace_changed";
|
|
637
660
|
cwd: string;
|
|
661
|
+
} & TaskEventIdentity) | ({
|
|
662
|
+
type: "wiring_manifest";
|
|
663
|
+
manifest: import("./wiring-manifest.js").WiringManifest;
|
|
638
664
|
} & TaskEventIdentity) | {
|
|
639
665
|
type: "done";
|
|
640
666
|
result: TaskResult;
|
|
641
667
|
};
|
|
668
|
+
export type HumanInputEvent = Extract<TaskEvent, {
|
|
669
|
+
type: "human_input";
|
|
670
|
+
}>;
|
|
642
671
|
export type CompactOutcome = "compacted" | "failed" | "mooted" | "noop" | "blocked" | "disabled";
|
|
643
672
|
export interface TaskStream extends AsyncIterable<TaskEvent> {
|
|
644
673
|
result(): Promise<TaskResult>;
|
|
645
674
|
suggestions(): Promise<string[]>;
|
|
646
675
|
steer(text: string, options?: {
|
|
647
676
|
trusted?: boolean;
|
|
677
|
+
actor?: ActorAssertion;
|
|
648
678
|
}): Promise<void>;
|
|
649
679
|
notify(payload: import("./task-notification.js").ExternalNotificationInput, opts?: {
|
|
650
680
|
priority?: import("./task-notification.js").SystemInjectionPriority;
|
|
@@ -798,6 +828,7 @@ export interface RunnerDeps {
|
|
|
798
828
|
toolPolicy?: import("./tool-policy.js").ToolPolicy;
|
|
799
829
|
onAsk?: import("./tool-policy.js").OnAsk;
|
|
800
830
|
onQuestion?: import("./ask-question.js").OnQuestion;
|
|
831
|
+
interactionPosture?: "interactive" | "headless";
|
|
801
832
|
lspManager?: import("./lsp.js").LspServerManager;
|
|
802
833
|
hooks?: import("./hooks.js").Hooks;
|
|
803
834
|
allowImageUrl?: (url: string) => boolean;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { RunnerDeps, TaskSpec } from "./types.js";
|
|
2
|
+
import { type StoreDurability } from "./checkpoint-store.js";
|
|
3
|
+
export type { StoreDurability };
|
|
4
|
+
export type ManifestDurability = "declared_durable" | "process_local";
|
|
5
|
+
export type WiringLegKind = "root" | "child" | "resume";
|
|
6
|
+
export type AskSeamForm = "callback" | "allow" | "deny" | "absent";
|
|
7
|
+
export type AskEffective = "human_reachable" | "auto_allow" | "auto_deny" | "park_only" | "unresolved";
|
|
8
|
+
export type QuestionChannelState = "wired" | "absent" | "stripped_bg_lane";
|
|
9
|
+
export type SeamProvenance = "spec" | "deps";
|
|
10
|
+
export type ParkLaneReason = "no_checkpoint_store" | "no_durable_approval_opt_in" | "no_force_durable_gate" | "no_armed_safety_vocabulary" | "await_runtime_caps" | "await_tool_vocabulary";
|
|
11
|
+
export interface WiringManifest {
|
|
12
|
+
schemaVersion: 1;
|
|
13
|
+
leg?: {
|
|
14
|
+
kind: WiringLegKind;
|
|
15
|
+
};
|
|
16
|
+
ask: {
|
|
17
|
+
form: AskSeamForm;
|
|
18
|
+
provenance?: SeamProvenance;
|
|
19
|
+
effective?: AskEffective;
|
|
20
|
+
};
|
|
21
|
+
question: {
|
|
22
|
+
wired: QuestionChannelState;
|
|
23
|
+
provenance?: SeamProvenance;
|
|
24
|
+
interactiveToolsWithoutDeliveryFace?: true;
|
|
25
|
+
};
|
|
26
|
+
interaction: {
|
|
27
|
+
posture: "interactive" | "headless" | "absent";
|
|
28
|
+
};
|
|
29
|
+
elicit: {
|
|
30
|
+
seamWired: boolean;
|
|
31
|
+
serversOptedIn: number;
|
|
32
|
+
};
|
|
33
|
+
parkLane: {
|
|
34
|
+
capable: boolean;
|
|
35
|
+
effective: boolean | "unresolved";
|
|
36
|
+
reasons: readonly ParkLaneReason[];
|
|
37
|
+
checkpointDurability?: ManifestDurability;
|
|
38
|
+
};
|
|
39
|
+
session: {
|
|
40
|
+
store: ManifestDurability;
|
|
41
|
+
};
|
|
42
|
+
fleet: {
|
|
43
|
+
backgroundAgentStore: boolean;
|
|
44
|
+
hostChildEventSink: boolean;
|
|
45
|
+
};
|
|
46
|
+
governance: {
|
|
47
|
+
audience: "operator";
|
|
48
|
+
lockedConfig: boolean;
|
|
49
|
+
compliance: boolean;
|
|
50
|
+
memoryAdmission: boolean;
|
|
51
|
+
retention: boolean;
|
|
52
|
+
};
|
|
53
|
+
configFingerprint?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface WiringFacts {
|
|
56
|
+
half: "static" | "effective";
|
|
57
|
+
leg?: WiringLegKind;
|
|
58
|
+
askForm: AskSeamForm;
|
|
59
|
+
askProvenance?: SeamProvenance;
|
|
60
|
+
questionWired: boolean;
|
|
61
|
+
questionProvenance?: SeamProvenance;
|
|
62
|
+
questionStrippedByEngine?: boolean;
|
|
63
|
+
interactiveToolsWithoutDeliveryFace?: boolean;
|
|
64
|
+
interactionPosture?: "interactive" | "headless";
|
|
65
|
+
elicitSeamWired: boolean;
|
|
66
|
+
elicitServersOptedIn: number;
|
|
67
|
+
parkCapable: boolean;
|
|
68
|
+
parkDurableApprovalOptIn: boolean;
|
|
69
|
+
parkForceDurableGate?: boolean;
|
|
70
|
+
parkSafetyVocabularyArmed?: boolean;
|
|
71
|
+
checkpointDurability?: StoreDurability;
|
|
72
|
+
sessionDurability: StoreDurability;
|
|
73
|
+
backgroundAgentStoreWired: boolean;
|
|
74
|
+
hostChildEventSinkWired: boolean;
|
|
75
|
+
lockedConfigWired: boolean;
|
|
76
|
+
complianceWired: boolean;
|
|
77
|
+
memoryAdmissionWired: boolean;
|
|
78
|
+
retentionPolicyWired: boolean;
|
|
79
|
+
}
|
|
80
|
+
export type StaticWiringDeps = Pick<RunnerDeps, "onAsk" | "onQuestion" | "interactionPosture" | "onElicit" | "checkpointStore" | "sessionStore" | "backgroundAgentStore" | "onBackgroundChildEvent" | "lockedConfig" | "compliancePostureResolver" | "memoryScopeAdmission" | "retentionPolicy">;
|
|
81
|
+
export type StaticWiringSpec = Pick<TaskSpec, "onAsk" | "onQuestion" | "checkpointStore" | "durableApproval" | "mcp" | "interactiveTools" | "interactionPosture">;
|
|
82
|
+
export declare function resolveDeclaredDurability(store: {
|
|
83
|
+
readonly durability?: StoreDurability;
|
|
84
|
+
} | undefined, storeName: string): StoreDurability;
|
|
85
|
+
export declare function deriveAskEffective(form: AskSeamForm, parkEffective: boolean | "unresolved"): AskEffective;
|
|
86
|
+
export declare function deriveWiringManifest(facts: WiringFacts): WiringManifest;
|
|
87
|
+
export declare function resolveAskSeamForm(spec: Pick<TaskSpec, "onAsk">, deps: Pick<RunnerDeps, "onAsk">): {
|
|
88
|
+
form: AskSeamForm;
|
|
89
|
+
provenance?: SeamProvenance;
|
|
90
|
+
};
|
|
91
|
+
export declare function resolveQuestionSeam(spec: Pick<TaskSpec, "onQuestion">, deps: Pick<RunnerDeps, "onQuestion">): {
|
|
92
|
+
wired: boolean;
|
|
93
|
+
provenance?: SeamProvenance;
|
|
94
|
+
};
|
|
95
|
+
export declare function countElicitOptIns(spec: Pick<TaskSpec, "mcp">): number;
|
|
96
|
+
export declare function resolveElicitSeam(deps: Pick<RunnerDeps, "onElicit">): boolean;
|
|
97
|
+
export declare function describeStaticWiring(deps: StaticWiringDeps, spec?: StaticWiringSpec): WiringManifest;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { canonicalize } from "./canonical-json.js";
|
|
3
|
+
import { resolveCheckpointStore } from "./checkpoint-store.js";
|
|
4
|
+
import { isLiveQuestionFace } from "./ask-question.js";
|
|
5
|
+
export function resolveDeclaredDurability(store, storeName) {
|
|
6
|
+
const declared = store?.durability;
|
|
7
|
+
if (declared === undefined)
|
|
8
|
+
return "process-local";
|
|
9
|
+
if (declared === "durable" || declared === "process-local")
|
|
10
|
+
return declared;
|
|
11
|
+
const e = new Error(`${storeName}.durability declares ${JSON.stringify(declared)} — not a recognized StoreDurability ` +
|
|
12
|
+
`("durable" | "process-local"). Fix the declaration; an unparseable durability cannot be folded to either arm.`);
|
|
13
|
+
e.code = "config.store_durability_invalid";
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
const manifestDurabilityOf = (d) => (d === "durable" ? "declared_durable" : "process_local");
|
|
17
|
+
export function deriveAskEffective(form, parkEffective) {
|
|
18
|
+
switch (form) {
|
|
19
|
+
case "callback":
|
|
20
|
+
return "human_reachable";
|
|
21
|
+
case "allow":
|
|
22
|
+
return "auto_allow";
|
|
23
|
+
case "deny":
|
|
24
|
+
return "auto_deny";
|
|
25
|
+
case "absent":
|
|
26
|
+
return parkEffective === true ? "park_only" : parkEffective === "unresolved" ? "unresolved" : "auto_deny";
|
|
27
|
+
default: {
|
|
28
|
+
const _exhaustive = form;
|
|
29
|
+
void _exhaustive;
|
|
30
|
+
throw new Error(`unreachable ask form ${String(form)}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function deriveParkLane(facts) {
|
|
35
|
+
if (!facts.parkCapable) {
|
|
36
|
+
return { capable: false, effective: false, reasons: ["no_checkpoint_store"] };
|
|
37
|
+
}
|
|
38
|
+
const durability = facts.checkpointDurability !== undefined ? { checkpointDurability: manifestDurabilityOf(facts.checkpointDurability) } : {};
|
|
39
|
+
if (facts.parkDurableApprovalOptIn || facts.parkForceDurableGate === true || facts.parkSafetyVocabularyArmed === true) {
|
|
40
|
+
return { capable: true, effective: true, reasons: [], ...durability };
|
|
41
|
+
}
|
|
42
|
+
const reasons = ["no_durable_approval_opt_in"];
|
|
43
|
+
const unresolved = facts.parkForceDurableGate === undefined || facts.parkSafetyVocabularyArmed === undefined;
|
|
44
|
+
if (facts.parkForceDurableGate === undefined)
|
|
45
|
+
reasons.push("await_runtime_caps");
|
|
46
|
+
else
|
|
47
|
+
reasons.push("no_force_durable_gate");
|
|
48
|
+
if (facts.parkSafetyVocabularyArmed === undefined)
|
|
49
|
+
reasons.push("await_tool_vocabulary");
|
|
50
|
+
else
|
|
51
|
+
reasons.push("no_armed_safety_vocabulary");
|
|
52
|
+
return { capable: true, effective: unresolved ? "unresolved" : false, reasons, ...durability };
|
|
53
|
+
}
|
|
54
|
+
export function deriveWiringManifest(facts) {
|
|
55
|
+
if (facts.half === "static" && facts.leg !== undefined) {
|
|
56
|
+
throw new Error("a static wiring manifest has no leg — leg identity is an effective-half fact");
|
|
57
|
+
}
|
|
58
|
+
if (facts.half === "effective" && facts.leg === undefined) {
|
|
59
|
+
throw new Error("an effective wiring manifest requires its leg kind");
|
|
60
|
+
}
|
|
61
|
+
if (facts.half === "effective" && (facts.parkForceDurableGate === undefined || facts.parkSafetyVocabularyArmed === undefined)) {
|
|
62
|
+
throw new Error("an effective wiring manifest requires the resolved park atoms (parkForceDurableGate, parkSafetyVocabularyArmed) — " +
|
|
63
|
+
"`unresolved` is a static-half fact; report the static half instead, or resolve the atoms first.");
|
|
64
|
+
}
|
|
65
|
+
const parkLane = deriveParkLane(facts);
|
|
66
|
+
const questionChannel = facts.questionWired
|
|
67
|
+
? "wired"
|
|
68
|
+
: facts.half === "effective" && facts.questionStrippedByEngine === true
|
|
69
|
+
? "stripped_bg_lane"
|
|
70
|
+
: "absent";
|
|
71
|
+
const manifest = {
|
|
72
|
+
schemaVersion: 1,
|
|
73
|
+
...(facts.leg !== undefined ? { leg: { kind: facts.leg } } : {}),
|
|
74
|
+
ask: {
|
|
75
|
+
form: facts.askForm,
|
|
76
|
+
...(facts.askProvenance !== undefined ? { provenance: facts.askProvenance } : {}),
|
|
77
|
+
...(facts.half === "effective" ? { effective: deriveAskEffective(facts.askForm, parkLane.effective) } : {}),
|
|
78
|
+
},
|
|
79
|
+
question: {
|
|
80
|
+
wired: questionChannel,
|
|
81
|
+
...(questionChannel === "wired" && facts.questionProvenance !== undefined ? { provenance: facts.questionProvenance } : {}),
|
|
82
|
+
...(facts.interactiveToolsWithoutDeliveryFace === true ? { interactiveToolsWithoutDeliveryFace: true } : {}),
|
|
83
|
+
},
|
|
84
|
+
interaction: { posture: facts.interactionPosture ?? "absent" },
|
|
85
|
+
elicit: { seamWired: facts.elicitSeamWired, serversOptedIn: facts.elicitServersOptedIn },
|
|
86
|
+
parkLane,
|
|
87
|
+
session: { store: manifestDurabilityOf(facts.sessionDurability) },
|
|
88
|
+
fleet: { backgroundAgentStore: facts.backgroundAgentStoreWired, hostChildEventSink: facts.hostChildEventSinkWired },
|
|
89
|
+
governance: {
|
|
90
|
+
audience: "operator",
|
|
91
|
+
lockedConfig: facts.lockedConfigWired,
|
|
92
|
+
compliance: facts.complianceWired,
|
|
93
|
+
memoryAdmission: facts.memoryAdmissionWired,
|
|
94
|
+
retention: facts.retentionPolicyWired,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
if (facts.half === "effective") {
|
|
98
|
+
const { leg: _leg, ...assembly } = manifest;
|
|
99
|
+
const { provenance: _askSeat, ...askForHash } = assembly.ask;
|
|
100
|
+
const { provenance: _questionSeat, ...questionForHash } = assembly.question;
|
|
101
|
+
manifest.configFingerprint = createHash("sha256")
|
|
102
|
+
.update(canonicalize({ ...assembly, ask: askForHash, question: questionForHash }))
|
|
103
|
+
.digest("hex")
|
|
104
|
+
.slice(0, 16);
|
|
105
|
+
}
|
|
106
|
+
return manifest;
|
|
107
|
+
}
|
|
108
|
+
export function resolveAskSeamForm(spec, deps) {
|
|
109
|
+
const seat = spec.onAsk !== undefined ? { value: spec.onAsk, provenance: "spec" } : deps.onAsk !== undefined ? { value: deps.onAsk, provenance: "deps" } : undefined;
|
|
110
|
+
if (seat === undefined)
|
|
111
|
+
return { form: "absent" };
|
|
112
|
+
const v = seat.value;
|
|
113
|
+
const form = typeof v === "function" ? "callback" : v === "allow" ? "allow" : v === "deny" ? "deny" : undefined;
|
|
114
|
+
if (form === undefined) {
|
|
115
|
+
const e = new Error(`the resolved onAsk seat (${seat.provenance}) holds ${JSON.stringify(v)} — not an OnAsk ` +
|
|
116
|
+
`("allow" | "deny" | approver function); refusing to classify it.`);
|
|
117
|
+
e.code = "config.interaction_wiring";
|
|
118
|
+
throw e;
|
|
119
|
+
}
|
|
120
|
+
return { form, provenance: seat.provenance };
|
|
121
|
+
}
|
|
122
|
+
export function resolveQuestionSeam(spec, deps) {
|
|
123
|
+
const seat = spec.onQuestion !== undefined ? { value: spec.onQuestion, provenance: "spec" } : deps.onQuestion !== undefined ? { value: deps.onQuestion, provenance: "deps" } : undefined;
|
|
124
|
+
if (seat === undefined)
|
|
125
|
+
return { wired: false };
|
|
126
|
+
if (typeof seat.value !== "function") {
|
|
127
|
+
const e = new Error(`the resolved onQuestion seat (${seat.provenance}) holds ${seat.value === null ? "null" : typeof seat.value} — not an OnQuestion ` +
|
|
128
|
+
`callback; refusing to report it as a wired question channel (omit the key, or wire a function).`);
|
|
129
|
+
e.code = "config.interaction_wiring";
|
|
130
|
+
throw e;
|
|
131
|
+
}
|
|
132
|
+
if (!isLiveQuestionFace(seat.value))
|
|
133
|
+
return { wired: false };
|
|
134
|
+
return { wired: true, provenance: seat.provenance };
|
|
135
|
+
}
|
|
136
|
+
export function countElicitOptIns(spec) {
|
|
137
|
+
return (spec.mcp ?? []).filter((s) => s.elicitation === true).length;
|
|
138
|
+
}
|
|
139
|
+
export function resolveElicitSeam(deps) {
|
|
140
|
+
if (deps.onElicit === undefined)
|
|
141
|
+
return false;
|
|
142
|
+
if (typeof deps.onElicit !== "function") {
|
|
143
|
+
const e = new Error(`RunnerDeps.onElicit holds ${deps.onElicit === null ? "null" : typeof deps.onElicit} — not an OnElicit ` +
|
|
144
|
+
`callback; refusing to report it as a wired elicitation seam (omit the key, or wire a function).`);
|
|
145
|
+
e.code = "config.interaction_wiring";
|
|
146
|
+
throw e;
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
export function describeStaticWiring(deps, spec = {}) {
|
|
151
|
+
const ask = resolveAskSeamForm(spec, deps);
|
|
152
|
+
const question = resolveQuestionSeam(spec, deps);
|
|
153
|
+
const checkpointStore = resolveCheckpointStore(spec, deps);
|
|
154
|
+
const capable = checkpointStore !== undefined;
|
|
155
|
+
return deriveWiringManifest({
|
|
156
|
+
half: "static",
|
|
157
|
+
askForm: ask.form,
|
|
158
|
+
...(ask.provenance !== undefined ? { askProvenance: ask.provenance } : {}),
|
|
159
|
+
questionWired: question.wired,
|
|
160
|
+
...(question.provenance !== undefined ? { questionProvenance: question.provenance } : {}),
|
|
161
|
+
...(() => {
|
|
162
|
+
const posture = spec.interactionPosture ?? deps.interactionPosture;
|
|
163
|
+
if (posture === undefined)
|
|
164
|
+
return {};
|
|
165
|
+
if (posture !== "interactive" && posture !== "headless") {
|
|
166
|
+
const e = new Error(`interactionPosture ${JSON.stringify(posture)} is not a recognized posture ("interactive" | "headless") — ` +
|
|
167
|
+
`an unevaluable declaration is refused loudly, never folded to either posture (or to absent).`);
|
|
168
|
+
e.code = "config.interaction_posture";
|
|
169
|
+
throw e;
|
|
170
|
+
}
|
|
171
|
+
return { interactionPosture: posture };
|
|
172
|
+
})(),
|
|
173
|
+
elicitSeamWired: resolveElicitSeam(deps),
|
|
174
|
+
elicitServersOptedIn: countElicitOptIns(spec),
|
|
175
|
+
parkCapable: capable,
|
|
176
|
+
parkDurableApprovalOptIn: spec.durableApproval !== undefined,
|
|
177
|
+
...(capable ? { checkpointDurability: resolveDeclaredDurability(checkpointStore, "checkpointStore") } : {}),
|
|
178
|
+
sessionDurability: resolveDeclaredDurability(deps.sessionStore, "sessionStore"),
|
|
179
|
+
backgroundAgentStoreWired: deps.backgroundAgentStore !== undefined,
|
|
180
|
+
hostChildEventSinkWired: deps.onBackgroundChildEvent !== undefined,
|
|
181
|
+
lockedConfigWired: deps.lockedConfig !== undefined,
|
|
182
|
+
complianceWired: deps.compliancePostureResolver !== undefined,
|
|
183
|
+
memoryAdmissionWired: deps.memoryScopeAdmission !== undefined,
|
|
184
|
+
retentionPolicyWired: deps.retentionPolicy !== undefined,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
@@ -428,7 +428,7 @@ Then, after </analysis>, write the summary. Your summary should include the foll
|
|
|
428
428
|
3. Files and Code Sections: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
|
|
429
429
|
4. Errors and fixes: List all errors that you ran into, and how you fixed them. Pay special attention to specific user feedback that you received, especially if the user told you to do something differently.
|
|
430
430
|
5. Problem Solving: Document problems solved and any ongoing troubleshooting efforts.
|
|
431
|
-
6. All user messages: List ALL user messages that are not tool results. These are critical for understanding the users' feedback and changing intent. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.
|
|
431
|
+
6. All user messages: List ALL user messages that are not tool results. These are critical for understanding the users' feedback and changing intent. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. When user messages carry speaker attribution labels (a leading [from "..."] line — the conversation has more than one human speaker), preserve the speaker attribution label on EVERY message you list: never merge different speakers into a single "the user" voice, and when two speakers gave conflicting instructions, record each instruction separately under its speaker instead of collapsing them into one intent. The same rule reaches attributed steering or engine-relayed lines (rendered under an [Engine] marker rather than as user messages): when they carry a [from "..."] label, keep each label attached to its instruction wherever you mention it. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.
|
|
432
432
|
7. Pending Tasks: Outline any pending tasks that you have explicitly been asked to work on.
|
|
433
433
|
8. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
|
|
434
434
|
9. Optional Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests or really old requests that were already completed without confirming with the user first.
|
|
@@ -473,7 +473,7 @@ First, inside an <analysis>...</analysis> block, note what is new since the prev
|
|
|
473
473
|
3. Files and Code Sections: [Preserve entries still relevant; add newly examined, modified, or created files with full code snippets where applicable]
|
|
474
474
|
4. Errors and fixes: [Preserve previous errors and fixes and add new ones; keep any user correction or "change of approach" feedback verbatim.]
|
|
475
475
|
5. Problem Solving: [Update problems solved and any ongoing troubleshooting efforts]
|
|
476
|
-
6. All user messages: [Preserve previously-recorded user messages VERBATIM and append any new ones that are not tool results, in order. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. To bound growth across repeated compactions, keep roughly the most recent 20 messages verbatim; older ones beyond that may be condensed to a single line each — but NEVER drop or paraphrase a user correction or change of direction. The exact words of recent messages are the strongest anti-drift signal. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.]
|
|
476
|
+
6. All user messages: [Preserve previously-recorded user messages VERBATIM and append any new ones that are not tool results, in order. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. When user messages carry speaker attribution labels (a leading [from "..."] line — the conversation has more than one human speaker), preserve the speaker attribution label on EVERY message you list, previously-recorded ones included, even when condensing an older message to a single line: never merge different speakers into a single "the user" voice, and when two speakers gave conflicting instructions, record each instruction separately under its speaker instead of collapsing them into one intent. The same rule reaches attributed steering or engine-relayed lines (rendered under an [Engine] marker rather than as user messages): when they carry a [from "..."] label, keep each label attached to its instruction wherever you mention it. To bound growth across repeated compactions, keep roughly the most recent 20 messages verbatim; older ones beyond that may be condensed to a single line each — but NEVER drop or paraphrase a user correction or change of direction. The exact words of recent messages are the strongest anti-drift signal. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.]
|
|
477
477
|
7. Pending Tasks: [Update based on progress — remove completed tasks, add newly requested ones]
|
|
478
478
|
8. Current Work: [Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant]
|
|
479
479
|
9. Optional Next Step: [Update based on current state. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request — include a direct verbatim quote of that request. Do not start on tangential requests or really old requests that were already completed.]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage, ImageContent, Model } from "../llm/index.js";
|
|
1
|
+
import type { ActorAssertion, AssistantMessage, ImageContent, Model } from "../llm/index.js";
|
|
2
2
|
import type { AgentMessage, AgentTool, LoopMalformedToolUseRecovery, LoopThinkingOnlyRecovery, LoopTruncatedOutputRecovery, QueueMode, ThinkingLevel } from "../loop/types.js";
|
|
3
3
|
import { type EngineSegment } from "../../core/untrusted-text.js";
|
|
4
4
|
import type { AbortResult, AgentHarnessEvent, AgentHarnessEventResultMap, AgentHarnessOptions, AgentHarnessOwnEvent, AgentHarnessResources, AgentHarnessStreamOptions, ExecutionEnv, PromptTemplate, Skill } from "./types.js";
|
|
@@ -8,6 +8,7 @@ export interface UserMessageProvenance {
|
|
|
8
8
|
engineMinted?: true;
|
|
9
9
|
provenance?: "engine-note";
|
|
10
10
|
enginePayload?: unknown;
|
|
11
|
+
actor?: ActorAssertion;
|
|
11
12
|
}
|
|
12
13
|
export interface HarnessLoopRecovery {
|
|
13
14
|
truncatedOutput?: LoopTruncatedOutputRecovery;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { snapshotActorAssertion, stripEngineMetadata } from "../llm/index.js";
|
|
1
2
|
import { runAgentLoop } from "../loop/agent-loop.js";
|
|
2
3
|
import { resolveAgentCoreStreamFn } from "../loop/runtime-deps.js";
|
|
3
4
|
import { normalizeEngineSegments } from "../../core/untrusted-text.js";
|
|
@@ -24,6 +25,12 @@ function createUserMessage(text, images, provenance) {
|
|
|
24
25
|
: {}),
|
|
25
26
|
...(provenance?.engineMinted === true && !engineNote ? { engineMinted: true } : {}),
|
|
26
27
|
...(engineNote ? { provenance: "engine-note" } : {}),
|
|
28
|
+
...(provenance?.actor !== undefined &&
|
|
29
|
+
typeof provenance.actor.id === "string" &&
|
|
30
|
+
provenance.actor.id.length > 0 &&
|
|
31
|
+
typeof provenance.actor.hostAsserted === "boolean"
|
|
32
|
+
? { actor: snapshotActorAssertion(provenance.actor) }
|
|
33
|
+
: {}),
|
|
27
34
|
};
|
|
28
35
|
}
|
|
29
36
|
const engineNotePayloads = new WeakMap();
|
|
@@ -455,7 +462,7 @@ export class AgentHarness {
|
|
|
455
462
|
...(this.streamingToolExecution === true && (this.getHandlers("tool_call")?.size ?? 0) === 0
|
|
456
463
|
? { streamingToolExecution: true }
|
|
457
464
|
: {}),
|
|
458
|
-
convertToLlm,
|
|
465
|
+
convertToLlm: (messages) => stripEngineMetadata(convertToLlm(messages)),
|
|
459
466
|
shouldStopAfterTurn: () => this._stopAfterTurn,
|
|
460
467
|
transformContext: async (messages) => {
|
|
461
468
|
const result = await this.emitHook({ type: "context", messages: [...messages] });
|
|
@@ -336,7 +336,9 @@ export interface SessionRepo<TMetadata extends SessionMetadata = SessionMetadata
|
|
|
336
336
|
delete(metadata: TMetadata): Promise<void>;
|
|
337
337
|
fork(source: TMetadata, options: SessionForkOptions & TCreateOptions): Promise<Session<TMetadata>>;
|
|
338
338
|
exportEntries?(sessionId: string): Promise<SessionTreeEntry[]>;
|
|
339
|
-
importEntries?(sessionId: string, owner: string | undefined, entries: SessionTreeEntry[]
|
|
339
|
+
importEntries?(sessionId: string, owner: string | undefined, entries: SessionTreeEntry[], options?: {
|
|
340
|
+
preserveActorAssertions?: boolean;
|
|
341
|
+
}): Promise<void>;
|
|
340
342
|
}
|
|
341
343
|
export interface JsonlSessionCreateOptions extends SessionCreateOptions {
|
|
342
344
|
cwd: string;
|
|
@@ -110,6 +110,12 @@ export interface Usage {
|
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
112
|
export type StopReason = "stop" | "length" | "toolUse" | "error" | "aborted";
|
|
113
|
+
export interface ActorAssertion {
|
|
114
|
+
id: string;
|
|
115
|
+
hostAsserted: boolean;
|
|
116
|
+
issuer?: string;
|
|
117
|
+
}
|
|
118
|
+
export declare function snapshotActorAssertion(actor: ActorAssertion): ActorAssertion;
|
|
113
119
|
export interface UserMessage {
|
|
114
120
|
role: "user";
|
|
115
121
|
content: string | (TextContent | ImageContent)[];
|
|
@@ -121,6 +127,7 @@ export interface UserMessage {
|
|
|
121
127
|
}>;
|
|
122
128
|
engineMinted?: true;
|
|
123
129
|
provenance?: "engine-note";
|
|
130
|
+
actor?: ActorAssertion;
|
|
124
131
|
}
|
|
125
132
|
export interface AssistantMessage {
|
|
126
133
|
role: "assistant";
|
package/dist/engine/llm/types.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
export function snapshotActorAssertion(actor) {
|
|
2
|
+
return {
|
|
3
|
+
id: actor.id,
|
|
4
|
+
hostAsserted: actor.hostAsserted,
|
|
5
|
+
...(actor.issuer !== undefined ? { issuer: actor.issuer } : {}),
|
|
6
|
+
};
|
|
7
|
+
}
|
|
1
8
|
export function stripEngineMetadata(messages) {
|
|
2
9
|
return messages.map((m) => {
|
|
3
10
|
if (m.role !== "user")
|
|
4
11
|
return m;
|
|
5
|
-
const { enginePrefixChars: _a, engineSegments: _b, engineMinted: _c, provenance: _d, ...rest } = m;
|
|
12
|
+
const { enginePrefixChars: _a, engineSegments: _b, engineMinted: _c, provenance: _d, actor: _e, ...rest } = m;
|
|
6
13
|
return rest;
|
|
7
14
|
});
|
|
8
15
|
}
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import { type SessionTreeEntry } from "../harness/types.js";
|
|
2
|
+
export interface ImportValidatorOptions {
|
|
3
|
+
preserveActorAssertions?: boolean;
|
|
4
|
+
}
|
|
2
5
|
export declare class StreamingImportValidator {
|
|
3
6
|
private readonly seen;
|
|
4
7
|
private readonly parentOf;
|
|
5
8
|
private rootCount;
|
|
6
9
|
private runningLeaf;
|
|
7
10
|
private done;
|
|
11
|
+
private readonly preserveActorAssertions;
|
|
12
|
+
constructor(options?: ImportValidatorOptions);
|
|
8
13
|
step(entry: SessionTreeEntry): void;
|
|
9
14
|
finish(): {
|
|
10
15
|
leafId: string | null;
|
|
11
16
|
};
|
|
12
17
|
}
|
|
13
|
-
export declare function validateEntriesForImport(entries: SessionTreeEntry[]): SessionTreeEntry[];
|
|
18
|
+
export declare function validateEntriesForImport(entries: SessionTreeEntry[], options?: ImportValidatorOptions): SessionTreeEntry[];
|