@sema-agent/core 7.5.0 → 7.5.1
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 +24 -0
- package/dist/core/auto-mode.d.ts +9 -0
- package/dist/core/auto-mode.js +11 -0
- package/dist/core/checkpoint-store.js +5 -1
- package/dist/core/runner/checkpoint-scope.d.ts +32 -0
- package/dist/core/runner/checkpoint-scope.js +4 -0
- package/dist/core/runner/contracts.d.ts +1878 -0
- package/dist/core/runner/contracts.js +1 -0
- package/dist/core/runner/denial-limit-arms.d.ts +1 -1
- package/dist/core/runner/derived-route-fallback.d.ts +34 -0
- package/dist/core/runner/derived-route-fallback.js +16 -0
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +170 -0
- package/dist/core/runner/prepare-caps-and-workflow.js +255 -0
- package/dist/core/runner/prepare-config-doors.d.ts +2 -10
- package/dist/core/runner/prepare-defer-classify.d.ts +86 -0
- package/dist/core/runner/prepare-defer-classify.js +107 -0
- package/dist/core/runner/prepare-delegation-surface.d.ts +104 -0
- package/dist/core/runner/prepare-delegation-surface.js +144 -0
- package/dist/core/runner/prepare-execution-env.d.ts +54 -0
- package/dist/core/runner/prepare-execution-env.js +86 -0
- package/dist/core/runner/prepare-file-history.d.ts +95 -0
- package/dist/core/runner/prepare-file-history.js +383 -0
- package/dist/core/runner/prepare-hands-readface.d.ts +5 -7
- package/dist/core/runner/prepare-hands-readface.js +1 -1
- package/dist/core/runner/prepare-inherited-gate.d.ts +268 -0
- package/dist/core/runner/prepare-inherited-gate.js +266 -0
- package/dist/core/runner/prepare-listings.d.ts +77 -0
- package/dist/core/runner/prepare-listings.js +76 -0
- package/dist/core/runner/prepare-lsp.d.ts +55 -0
- package/dist/core/runner/prepare-lsp.js +27 -0
- package/dist/core/runner/prepare-memory.d.ts +1 -1
- package/dist/core/runner/prepare-offload-wrappers.d.ts +62 -0
- package/dist/core/runner/prepare-offload-wrappers.js +45 -0
- package/dist/core/runner/prepare-project-context.d.ts +131 -0
- package/dist/core/runner/prepare-project-context.js +150 -0
- package/dist/core/runner/prepare-prompt-inputs.d.ts +138 -0
- package/dist/core/runner/prepare-prompt-inputs.js +141 -0
- package/dist/core/runner/prepare-protocol-tools.d.ts +91 -0
- package/dist/core/runner/prepare-protocol-tools.js +182 -0
- package/dist/core/runner/prepare-question-face.d.ts +119 -0
- package/dist/core/runner/prepare-question-face.js +83 -0
- package/dist/core/runner/prepare-run-refs.d.ts +89 -0
- package/dist/core/runner/prepare-run-refs.js +39 -0
- package/dist/core/runner/prepare-safety-scan.d.ts +3 -2
- package/dist/core/runner/prepare-task.d.ts +11 -1846
- package/dist/core/runner/prepare-task.js +83 -2366
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +111 -0
- package/dist/core/runner/prepare-tool-disclosure-mount.js +219 -0
- package/dist/core/runner/prepare-wiring-manifest.d.ts +184 -0
- package/dist/core/runner/prepare-wiring-manifest.js +240 -0
- package/dist/core/runner/prepare-workspace-restore.d.ts +1 -27
- package/dist/core/runner/prepare-workspace-restore.js +1 -22
- package/dist/core/runner/rollback-stack.d.ts +32 -0
- package/dist/core/runner/rollback-stack.js +30 -0
- package/dist/core/runner/workspace-path.d.ts +33 -0
- package/dist/core/runner/workspace-path.js +22 -0
- package/dist/core/tool-policy.d.ts +16 -0
- package/dist/core/tool-policy.js +3 -0
- package/dist/core/types.d.ts +2 -2
- package/dist/core/write-protect.js +3 -2
- package/package.json +6 -2
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { formatLocalDate } from "../../prompts/default.js";
|
|
2
|
+
import { SKILL_TOOL_NAME } from "./synthetic-tools.js";
|
|
3
|
+
import { renderAgentListingDelta } from "./turn-attachments.js";
|
|
4
|
+
export function prepareListings(input) {
|
|
5
|
+
const { spec, tools, onceLedger, sessionId, toolFaceSnapshot, activeTools, resume, skillsListing, listingRideRef, renderWithDate, envFacts, tzValid, userTz } = input;
|
|
6
|
+
if (spec.agents !== undefined && spec.agents.length > 0) {
|
|
7
|
+
const known = new Set(tools.flatMap((t) => [t.name, ...(t.aliases ?? [])]));
|
|
8
|
+
for (const def of spec.agents) {
|
|
9
|
+
const unknownAllow = (def.allowTools ?? []).filter((n) => n !== "*" && !known.has(n));
|
|
10
|
+
if (unknownAllow.length > 0) {
|
|
11
|
+
try {
|
|
12
|
+
onceLedger.onError(new Error(`TaskSpec.agents: agent "${def.name}" allows tool(s) ${unknownAllow.join(", ")} not present in this task's assembled roster — likely a typo (the entry would be item-filtered at spawn; the agent stays usable). Advisory only: the delegation pool can differ from this roster, so a tool mounted only on the delegation tool or produced by per-spawn extraTools makes this spurious.`), { phase: "config", sessionId });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const n of def.denyTools ?? []) {
|
|
18
|
+
if (n === "*")
|
|
19
|
+
continue;
|
|
20
|
+
if (!known.has(n)) {
|
|
21
|
+
const e = new Error(`TaskSpec.agents: agent "${def.name}" declares tool "${n}" in its denied tools, but no such tool exists in this deployment — fix the agent's tools list or mount the tool.`);
|
|
22
|
+
e.code = "config.agent.unknown_tool";
|
|
23
|
+
throw e;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const rosterBearingSpec = (spec.tools ?? []).find((t) => t.agentListing !== undefined && t.agentListing.length > 0);
|
|
29
|
+
const rosterFaceDeferred = rosterBearingSpec !== undefined &&
|
|
30
|
+
!(toolFaceSnapshot.exclude?.includes(rosterBearingSpec.name) ?? false) &&
|
|
31
|
+
(toolFaceSnapshot.defer?.includes(rosterBearingSpec.name) ?? false) &&
|
|
32
|
+
!activeTools.has(rosterBearingSpec.name);
|
|
33
|
+
const agentListingSpec = rosterBearingSpec !== undefined &&
|
|
34
|
+
!rosterFaceDeferred &&
|
|
35
|
+
!(toolFaceSnapshot.exclude?.includes(rosterBearingSpec.name) ?? false)
|
|
36
|
+
? rosterBearingSpec
|
|
37
|
+
: undefined;
|
|
38
|
+
const agentListing = agentListingSpec
|
|
39
|
+
? {
|
|
40
|
+
entries: agentListingSpec.agentListing,
|
|
41
|
+
toolName: agentListingSpec.name,
|
|
42
|
+
seedAnnounced: resume !== undefined || spec.sessionId !== undefined,
|
|
43
|
+
...(agentListingSpec.agentModels !== undefined ? { models: agentListingSpec.agentModels } : {}),
|
|
44
|
+
}
|
|
45
|
+
:
|
|
46
|
+
!rosterFaceDeferred && ((resume?.seed.announcedListings?.agents?.length ?? 0) > 0 || spec.sessionId !== undefined)
|
|
47
|
+
?
|
|
48
|
+
{
|
|
49
|
+
entries: [],
|
|
50
|
+
toolName: (spec.tools ?? []).find((t) => t.agentListing !== undefined)?.name ?? "Agent",
|
|
51
|
+
seedAnnounced: true,
|
|
52
|
+
}
|
|
53
|
+
: undefined;
|
|
54
|
+
if (spec.attachments?.agentListing === false && agentListing !== undefined && agentListing.entries.length > 0) {
|
|
55
|
+
onceLedger.onError(new Error(`attachments.agentListing is explicitly false but the "${agentListing.toolName}" delegation tool mounts a ${agentListing.entries.length}-type roster — the model will never see the agent-type listing its tool description points to.`), { phase: "config", sessionId });
|
|
56
|
+
}
|
|
57
|
+
if (spec.attachments?.skillsListing === false && skillsListing !== undefined && skillsListing.entries.length > 0) {
|
|
58
|
+
onceLedger.onError(new Error(`attachments.skillsListing is explicitly false but ${skillsListing.entries.length} skill(s) are mounted — the model will never see the skills listing the ${SKILL_TOOL_NAME} tool description points to.`), { phase: "config", sessionId });
|
|
59
|
+
}
|
|
60
|
+
const announcedListingsRef = onceLedger.arms();
|
|
61
|
+
if (rosterFaceDeferred && rosterBearingSpec !== undefined) {
|
|
62
|
+
const rideEntries = rosterBearingSpec.agentListing;
|
|
63
|
+
const rideModels = rosterBearingSpec.agentModels;
|
|
64
|
+
listingRideRef.current = (newly) => {
|
|
65
|
+
if (!newly.includes(rosterBearingSpec.name))
|
|
66
|
+
return undefined;
|
|
67
|
+
if ((announcedListingsRef.agents?.length ?? 0) > 0)
|
|
68
|
+
return undefined;
|
|
69
|
+
return renderAgentListingDelta({ announcedAgentTypes: undefined }, rideEntries, rosterBearingSpec.name, rideModels);
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const dateChange = renderWithDate
|
|
73
|
+
? { legDate: envFacts.date, today: () => formatLocalDate(new Date(), tzValid ? userTz : undefined) }
|
|
74
|
+
: undefined;
|
|
75
|
+
return { agentListing, announcedListingsRef, dateChange };
|
|
76
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/390 §1.2 M8 — prepareTask's LSP phase, verbatim from the driver: the manager fold (spec > deps), the
|
|
3
|
+
* LSP tool mount over the per-task env with its git-ignore filter, the diagnostics lane behind its four
|
|
4
|
+
* preconditions (a manager whose sessions feed a registry, write-capable hands, not opted out), the run-scoped
|
|
5
|
+
* registry key, and the edit nudge (raw path → the SAME resolution the tool leg uses → registry reset +
|
|
6
|
+
* session didChange). No manager ⇒ nothing mounts and both lane seats are undefined. The interface is the
|
|
7
|
+
* dependency list the segment had implicitly (design/238 R-1).
|
|
8
|
+
*
|
|
9
|
+
* SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL: the stretch has no await, so the phase adds no yield between the
|
|
10
|
+
* fork-governance note before it and the memory trio's occupancy read after it (design/390 §1.5 S1: a stretch
|
|
11
|
+
* with no await is extracted as a sync function — an `async` wrapper would open a microtask window).
|
|
12
|
+
* Read-stability of the host handles for the call: {@link RunInternals} (`@contract prepare.deps-read-stable`).
|
|
13
|
+
*/
|
|
14
|
+
import type { AgentTool, ExecutionEnv } from "../../internal/harness.js";
|
|
15
|
+
import type { LspDiagnosticsRegistry } from "../lsp-diagnostics.js";
|
|
16
|
+
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
17
|
+
import type { Prepared } from "./contracts.js";
|
|
18
|
+
export interface PrepareLspInput {
|
|
19
|
+
/** borrowed-readonly — the REBOUND spec. Read: `lspManager` (the per-task manager, outranks the deployment's),
|
|
20
|
+
* `lspDiagnostics` (the lane's opt-out), `handsReadOnly` (a read-only run has no lane). Never mutated. */
|
|
21
|
+
spec: Pick<TaskSpec, "lspManager" | "lspDiagnostics" | "handsReadOnly">;
|
|
22
|
+
/** borrowed-readonly — the deployment's manager seat (read only when the spec carries none). */
|
|
23
|
+
deps: Pick<RunnerDeps, "lspManager">;
|
|
24
|
+
/** borrowed-readonly — the run's resolved env: the tool's in-env server and git-ignore filter, and the
|
|
25
|
+
* session lookup the nudge performs. */
|
|
26
|
+
executionEnv: ExecutionEnv;
|
|
27
|
+
/** borrowed-readonly — the SETTLED task root: the tool's git-ignore root, and the nudge's resolution base when
|
|
28
|
+
* no cwd is tracked. */
|
|
29
|
+
taskRootFinal: string;
|
|
30
|
+
/** borrowed-readonly — whether a real fs env is present (the lane's hands precondition). */
|
|
31
|
+
handsEnabled: boolean;
|
|
32
|
+
/** borrowed-readonly — the acquired session id: the run's key into the deployment-shared registry. */
|
|
33
|
+
sessionId: string;
|
|
34
|
+
/** borrowed-readonly — the tracked-cwd cell the hands band writes; the nudge READS `current` per call as its
|
|
35
|
+
* resolution base (identity is the contract — the band's `cd` handling writes this exact cell). */
|
|
36
|
+
handsCwdRef: Prepared["cwdRef"];
|
|
37
|
+
/** borrowed-mutable — the run's shared roster (identity is the contract). Writer here: ONE push (the LSP tool)
|
|
38
|
+
* when a manager exists. */
|
|
39
|
+
tools: AgentTool[];
|
|
40
|
+
/** borrowed-mutable — the env-hand membership set the read-posture observer projects; writer here: `add("LSP")`
|
|
41
|
+
* on the mount. */
|
|
42
|
+
envHandToolNames: Set<string>;
|
|
43
|
+
}
|
|
44
|
+
export interface PrepareLspResult {
|
|
45
|
+
/** borrowed-readonly — the manager's diagnostics registry when the lane is live, else undefined (the
|
|
46
|
+
* registry is a DEPLOYMENT object shared by every task; this run reads and resets it under its own key). */
|
|
47
|
+
lspDiagnostics: LspDiagnosticsRegistry | undefined;
|
|
48
|
+
/** owned — the edit nudge (raw path in), or undefined when the lane is not live. */
|
|
49
|
+
nudgeLspOnEdit: ((rawPath: string) => void) | undefined;
|
|
50
|
+
/** borrowed-readonly — the run's registry key (= the session id): a session hosts one run at a time and the
|
|
51
|
+
* run loop releases the key at the terminal. */
|
|
52
|
+
lspRunIdent: string;
|
|
53
|
+
}
|
|
54
|
+
/** The M8 phase body — prepareTask's LSP stretch, verbatim (see the module header). */
|
|
55
|
+
export declare function prepareLsp(input: PrepareLspInput): PrepareLspResult;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createLspTool, gitCheckIgnoreFilter, resolveLspPath } from "../lsp.js";
|
|
2
|
+
import { pathToUri } from "../lsp-protocol.js";
|
|
3
|
+
export function prepareLsp(input) {
|
|
4
|
+
const { spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef, tools, envHandToolNames } = input;
|
|
5
|
+
const lspManager = spec.lspManager ?? deps.lspManager;
|
|
6
|
+
if (lspManager) {
|
|
7
|
+
const lspRoot = taskRootFinal;
|
|
8
|
+
tools.push(createLspTool(lspManager, { isPathIgnored: gitCheckIgnoreFilter(executionEnv, lspRoot), env: executionEnv }));
|
|
9
|
+
envHandToolNames.add("LSP");
|
|
10
|
+
}
|
|
11
|
+
const lspDiagnostics = spec.lspDiagnostics !== false && lspManager?.diagnostics !== undefined && handsEnabled && spec.handsReadOnly !== true
|
|
12
|
+
? lspManager.diagnostics
|
|
13
|
+
: undefined;
|
|
14
|
+
const lspRunIdent = sessionId;
|
|
15
|
+
const nudgeLspOnEdit = lspDiagnostics
|
|
16
|
+
? (rawPath) => {
|
|
17
|
+
const baseDir = handsCwdRef?.current ?? taskRootFinal;
|
|
18
|
+
const filePath = resolveLspPath(rawPath, baseDir);
|
|
19
|
+
lspDiagnostics.fileEdited(lspRunIdent, pathToUri(filePath));
|
|
20
|
+
void lspManager
|
|
21
|
+
.sessionFor(filePath, undefined, executionEnv)
|
|
22
|
+
.then((session) => session?.notifyFileChanged?.(filePath))
|
|
23
|
+
.catch(() => undefined);
|
|
24
|
+
}
|
|
25
|
+
: undefined;
|
|
26
|
+
return { lspDiagnostics, nudgeLspOnEdit, lspRunIdent };
|
|
27
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BeforeWriteHook, EffectiveMemoryScopes, RunnerDeps, TaskSpec, ToolSpec } from "../types.js";
|
|
2
2
|
import { type CaptureEntitlementInput, type MemoryCapturePosture } from "./memory-capture-optout.js";
|
|
3
|
-
import type { Prepared } from "./
|
|
3
|
+
import type { Prepared } from "./contracts.js";
|
|
4
4
|
export interface PrepareMemoryInput {
|
|
5
5
|
spec: TaskSpec;
|
|
6
6
|
deps: RunnerDeps;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/390 §1.2 M0 (the offload half of the prelude) — prepareTask's nested-usage accumulator, the
|
|
3
|
+
* large-tool-result offload store resolution and the THREE offload wrappers every later mount site
|
|
4
|
+
* applies (caller tools, first-party hand tools, remote MCP/A2A peers), verbatim from the driver.
|
|
5
|
+
*
|
|
6
|
+
* SYNCHRONOUS by construction: the segment held no await in the driver, and a phase that yields where
|
|
7
|
+
* the driver did not would open a microtask window between two steps that used to be adjacent (the
|
|
8
|
+
* design/238 T1 posture). Nothing here touches the store — the wrappers close over it and only the
|
|
9
|
+
* wrapped tools' `execute` reach it, at run time.
|
|
10
|
+
*
|
|
11
|
+
* What stays in the driver: the trust-axis choice of `offloadScope` (`spec.principal ?? "default"`)
|
|
12
|
+
* and its disclosure, and the reserved-name door that FOLLOWS these wrappers (it awaits a bounded
|
|
13
|
+
* session forget, so it belongs with the driver's other refusal legs).
|
|
14
|
+
*/
|
|
15
|
+
import { type ToolResultStore } from "../tool-result-store.js";
|
|
16
|
+
import type { AgentTool } from "../../internal/harness.js";
|
|
17
|
+
import type { NestedUsage, NestedUsageAccum, RunnerDeps, TaskSpec } from "../types.js";
|
|
18
|
+
import type { PrepareResume } from "./contracts.js";
|
|
19
|
+
export interface PrepareOffloadWrappersInput {
|
|
20
|
+
/** borrowed-readonly — the REBOUND spec (the config-doors result); read for the per-task coarse
|
|
21
|
+
* offload knob only. */
|
|
22
|
+
spec: Pick<TaskSpec, "toolResultThresholdChars">;
|
|
23
|
+
/** borrowed-readonly — the deployment's coarse offload knob and its injected store (used AS-IS when
|
|
24
|
+
* present; a Runner-shared instance is viewed per task, see the body). */
|
|
25
|
+
deps: Pick<RunnerDeps, "toolResultThresholdChars" | "toolResultStore">;
|
|
26
|
+
/** borrowed-readonly — the resume leg, read for the checkpoint seed's nested-usage snapshot so
|
|
27
|
+
* delegated cost spent before a suspend is not lost; `undefined` on a fresh run. */
|
|
28
|
+
resume: Pick<PrepareResume, "seed"> | undefined;
|
|
29
|
+
/** borrowed-readonly — the run's TRUST identity (`spec.principal ?? "default"`, minted by the
|
|
30
|
+
* driver): the namespace a Runner-shared store is scoped under. Never the registry domain. */
|
|
31
|
+
offloadScope: string;
|
|
32
|
+
/** borrowed-readonly — the acquired session id, the offload wrapper's ref-minting coordinate. */
|
|
33
|
+
sessionId: string;
|
|
34
|
+
}
|
|
35
|
+
export interface PrepareOffloadWrappersResult {
|
|
36
|
+
/** borrowed-mutable — the run's nested sub-run usage accumulator (`Prepared.nestedStats`).
|
|
37
|
+
* Mutation owners after this call: `reportUsage` below (the only writer — every delegation tool
|
|
38
|
+
* reports through it via the tool ctx); the driver reads it into `Prepared`. */
|
|
39
|
+
nestedStats: NestedUsageAccum;
|
|
40
|
+
/** borrowed-readonly — the one writer of `nestedStats`; the driver threads it onto the tool ctx. */
|
|
41
|
+
reportUsage: (u: NestedUsage) => void;
|
|
42
|
+
/** borrowed-readonly — the store the wrappers close over, or `undefined` when offload is disabled
|
|
43
|
+
* (threshold 0 / non-finite). The driver reads it for the reserved-name door, the ReadToolResult
|
|
44
|
+
* mount, the durable-suspend gate and the compaction lane. Not a resource: nothing to release. */
|
|
45
|
+
offloadStore: ToolResultStore | undefined;
|
|
46
|
+
/** borrowed-mutable — the LIVE "currently callable tools" accessor cell the offload preview's
|
|
47
|
+
* pageback hint reads. Mutation owners after this call: the deferred-disclosure branch of the
|
|
48
|
+
* driver sets `.current` once the deferred/active sets exist; nothing else writes it. */
|
|
49
|
+
offloadReachableToolsRef: {
|
|
50
|
+
current?: () => ReadonlySet<string>;
|
|
51
|
+
};
|
|
52
|
+
/** borrowed-readonly — wrap a CALLER tool (per-tool `offload` / `offloadThresholdChars` honored). */
|
|
53
|
+
maybeOffload: (tool: AgentTool, perTool?: {
|
|
54
|
+
offload?: boolean;
|
|
55
|
+
offloadThresholdChars?: number;
|
|
56
|
+
}) => AgentTool;
|
|
57
|
+
/** borrowed-readonly — wrap a FIRST-PARTY mount (the per-tool persistence table; Read/Write exempt). */
|
|
58
|
+
firstPartyOffload: (tool: AgentTool) => AgentTool;
|
|
59
|
+
/** borrowed-readonly — wrap a REMOTE-PEER mount (MCP `_meta` size declaration, else 50K). */
|
|
60
|
+
remoteToolOffload: (tool: AgentTool) => AgentTool;
|
|
61
|
+
}
|
|
62
|
+
export declare function prepareOffloadWrappers(input: PrepareOffloadWrappersInput): PrepareOffloadWrappersResult;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, firstPartyOffloadPolicy, InMemoryToolResultStore, RunnerSharedToolResultStore, ScopedToolResultStore, withToolResultOffload, } from "../tool-result-store.js";
|
|
2
|
+
export function prepareOffloadWrappers(input) {
|
|
3
|
+
const { spec, deps, resume, offloadScope, sessionId } = input;
|
|
4
|
+
const nestedStats = { tokens: 0, turns: 0, tasks: 0, costMicroUsd: 0, anyUnpriced: false };
|
|
5
|
+
if (resume) {
|
|
6
|
+
nestedStats.tokens = resume.seed.nestedStats.tokens;
|
|
7
|
+
nestedStats.turns = resume.seed.nestedStats.turns;
|
|
8
|
+
nestedStats.tasks = resume.seed.nestedStats.tasks;
|
|
9
|
+
nestedStats.costMicroUsd = resume.seed.nestedStats.costMicroUsd;
|
|
10
|
+
nestedStats.anyUnpriced = resume.seed.nestedStats.anyUnpriced ?? true;
|
|
11
|
+
}
|
|
12
|
+
const reportUsage = (u) => {
|
|
13
|
+
nestedStats.tokens += u.tokens;
|
|
14
|
+
nestedStats.turns += u.turns;
|
|
15
|
+
nestedStats.tasks += u.tasks;
|
|
16
|
+
nestedStats.costMicroUsd += u.costMicroUsd ?? 0;
|
|
17
|
+
if (u.costMicroUsd === undefined)
|
|
18
|
+
nestedStats.anyUnpriced = true;
|
|
19
|
+
};
|
|
20
|
+
const explicitGlobalThreshold = spec.toolResultThresholdChars ?? deps.toolResultThresholdChars;
|
|
21
|
+
const offloadThreshold = explicitGlobalThreshold ?? DEFAULT_TOOL_RESULT_THRESHOLD_CHARS;
|
|
22
|
+
const offloadEnabled = Number.isFinite(offloadThreshold) && offloadThreshold > 0;
|
|
23
|
+
const rawOffloadStore = offloadEnabled ? (deps.toolResultStore ?? new InMemoryToolResultStore()) : undefined;
|
|
24
|
+
const offloadStore = rawOffloadStore instanceof RunnerSharedToolResultStore
|
|
25
|
+
? new ScopedToolResultStore(rawOffloadStore, offloadScope)
|
|
26
|
+
: rawOffloadStore;
|
|
27
|
+
const offloadReachableToolsRef = {};
|
|
28
|
+
const maybeOffload = (tool, perTool) => {
|
|
29
|
+
if (!offloadStore || perTool?.offload === false)
|
|
30
|
+
return tool;
|
|
31
|
+
return withToolResultOffload(tool, offloadStore, perTool?.offloadThresholdChars ?? offloadThreshold, sessionId, () => offloadReachableToolsRef.current?.());
|
|
32
|
+
};
|
|
33
|
+
const firstPartyOffload = (tool) => {
|
|
34
|
+
const policy = firstPartyOffloadPolicy(tool.name);
|
|
35
|
+
if (policy.offload === false)
|
|
36
|
+
return maybeOffload(tool, policy);
|
|
37
|
+
return maybeOffload(tool, explicitGlobalThreshold === undefined ? policy : undefined);
|
|
38
|
+
};
|
|
39
|
+
const remoteToolOffload = (tool) => {
|
|
40
|
+
if (explicitGlobalThreshold !== undefined)
|
|
41
|
+
return maybeOffload(tool);
|
|
42
|
+
return maybeOffload(tool, { offloadThresholdChars: tool.mcpMaxResultSizeChars ?? 50_000 });
|
|
43
|
+
};
|
|
44
|
+
return { nestedStats, reportUsage, offloadStore, offloadReachableToolsRef, maybeOffload, firstPartyOffload, remoteToolOffload };
|
|
45
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* design/390 M9 — prepareTask's PROJECT-CONTEXT phase: the deployment's project memory snapshot (the
|
|
3
|
+
* `loadProjectMemory` seam: phase derivation, instruction sources, the framed + fenced project layer
|
|
4
|
+
* appended to the memory block), the skills roster (declaration rank, normalization, the 1MB load gate,
|
|
5
|
+
* the manifest-scope door, the `skill` tool mount), the two built-in memory pairs' mount-or-yield
|
|
6
|
+
* (shared-memory pair, engine-memory pair), and the skills-listing projection the run loop announces.
|
|
7
|
+
* The body is the driver's stretch moved verbatim; the interface below is the dependency list it had
|
|
8
|
+
* implicitly (design/238 R-1: a new read is an Input field, i.e. a review event).
|
|
9
|
+
*
|
|
10
|
+
* ASYNC BY CONTENT: the stretch awaits the session branch read, the seam itself and the read-state
|
|
11
|
+
* seeding (all inside the `loadProjectMemory` arm). It already sits past prepareTask's first await, so
|
|
12
|
+
* the one extra microtask the driver's `await` adds on the seam-less path opens no window any caller
|
|
13
|
+
* could reach (design/390 §1.5 S1 synchronicity rule: only pre-first-await stretches must stay sync).
|
|
14
|
+
*
|
|
15
|
+
* Throws pass through unchanged: `config.reserved_tool_name` (a caller tool named like the skill tool
|
|
16
|
+
* while skills are present) is the only refusal here; the seam's own throw and the seeding's are
|
|
17
|
+
* caught and forwarded to `deps.onError` (best-effort, never block the task).
|
|
18
|
+
*/
|
|
19
|
+
import type { AgentTool } from "../../internal/harness.js";
|
|
20
|
+
import type { StoredSession } from "../session.js";
|
|
21
|
+
import type { RunnerDeps, TaskSpec, ToolSpec } from "../types.js";
|
|
22
|
+
import type { ActiveSkillScope } from "./active-skill-scope.js";
|
|
23
|
+
import type { AnnounceOnceSink, Prepared, PrepareResume, RunInternals, ToolFaceSnapshot } from "./contracts.js";
|
|
24
|
+
import { normalizeSkills } from "./synthetic-tools.js";
|
|
25
|
+
/**
|
|
26
|
+
* The ONE "has this session seen conversation?" predicate — the freshness question is asked three
|
|
27
|
+
* times in one prepare (project-memory phase, design/148 center adoption, the epoch-pin
|
|
28
|
+
* discriminator), and an entry-COUNT proxy at ANY of them re-creates the same lie: a host may write
|
|
29
|
+
* session_info / model_change / … rows before the first turn (naming a new chat, recording a model
|
|
30
|
+
* pick), and none of that is evidence of a prior session (5.29 merge-rescan: the count proxy
|
|
31
|
+
* survived at the adoption arm after the pin arm was fixed, silently costing a pre-named session
|
|
32
|
+
* its published center prompt for life). Conversation content — and only that — is the evidence.
|
|
33
|
+
*/
|
|
34
|
+
export declare function hasConversationContent(branch: ReadonlyArray<{
|
|
35
|
+
type: string;
|
|
36
|
+
}>): boolean;
|
|
37
|
+
export interface PrepareProjectContextInput {
|
|
38
|
+
/** borrowed-readonly — the deployment seams this phase reads: `loadProjectMemory` (the snapshot),
|
|
39
|
+
* `onError` (the operator lane for a throwing seam / seeding / oversize skill), `sharedMemoryStores`
|
|
40
|
+
* (the shared-memory pair's switch: wired ⇒ mount). Receiver preserved (`deps.onError?.(…)`). */
|
|
41
|
+
deps: Pick<RunnerDeps, "loadProjectMemory" | "onError" | "sharedMemoryStores">;
|
|
42
|
+
/** borrowed-readonly — the REBOUND spec (`spec′`). Read: `sessionId` (phase derivation + the
|
|
43
|
+
* continuation projections), `skills` (the roster), `principal` (the shared-memory tools' trusted
|
|
44
|
+
* identity). Never mutated. */
|
|
45
|
+
spec: Pick<TaskSpec, "sessionId" | "skills" | "principal">;
|
|
46
|
+
/** borrowed-readonly — trusted internals: `agentName` (seam ctx), `inheritedManifestScope` (the
|
|
47
|
+
* parent's active skill frames, seeded as the base of the LIFO). `undefined` on a standalone prepare. */
|
|
48
|
+
internals: Pick<RunInternals, "agentName" | "inheritedManifestScope"> | undefined;
|
|
49
|
+
/** borrowed-readonly — the acquired session; only `getBranch()` is read (phase derivation walk).
|
|
50
|
+
* The read is best-effort: a throw keeps the provisional phase. */
|
|
51
|
+
session: Pick<StoredSession, "getBranch">;
|
|
52
|
+
/** borrowed-readonly — the acquired session's id (seam ctx cache key; operator-line context). */
|
|
53
|
+
sessionId: string;
|
|
54
|
+
/** borrowed-readonly — `spec.taskId ?? sessionId`: the shared-memory tools' trusted task identity. */
|
|
55
|
+
hostTaskId: string;
|
|
56
|
+
/** borrowed-readonly — the FINAL task root (post-restore): the seam's `cwd`. */
|
|
57
|
+
taskRootFinal: string;
|
|
58
|
+
/** borrowed-readonly — whether a real execution env is mounted (seam ctx flag). */
|
|
59
|
+
handsEnabled: boolean;
|
|
60
|
+
/** borrowed-readonly — the leg's effective-delegation facts; only `isNonForkChild` is read (the
|
|
61
|
+
* seam's `isSubagent` — one derivation shared with the prompt fact, never re-derived here). */
|
|
62
|
+
delegation: {
|
|
63
|
+
readonly isNonForkChild: boolean;
|
|
64
|
+
};
|
|
65
|
+
/** borrowed-readonly — the hands phase's read-state seeding closure (CREATED there, CALLED here for
|
|
66
|
+
* the snapshot's declared `seededFiles`); `undefined` on a hands-less task = nothing to seed. */
|
|
67
|
+
seedContextFiles: ((files: ReadonlyArray<{
|
|
68
|
+
path: string;
|
|
69
|
+
content: string;
|
|
70
|
+
}>) => Promise<void>) | undefined;
|
|
71
|
+
/** borrowed-readonly — the memory phase's composed block, as returned (recall discipline + engine
|
|
72
|
+
* files). This phase APPENDS the project layer and hands the result back as
|
|
73
|
+
* {@link PrepareProjectContextResult.memoryBlock}; the input value itself is never mutated. */
|
|
74
|
+
memoryBlockFromEngine: string | undefined;
|
|
75
|
+
/** borrowed-mutable — the run's LIFO skill-scope stack (identity is the contract: the scope policy
|
|
76
|
+
* and the `skill` tool alias this exact object). Mutated here: `push` of every inherited parent
|
|
77
|
+
* frame; after this phase only the `skill` tool's execute pushes/pops. */
|
|
78
|
+
skillScope: ActiveSkillScope;
|
|
79
|
+
/** borrowed-mutable — the shared mount array (later refs alias it; in-place contract). Mutated
|
|
80
|
+
* here: `push` of the `skill` tool, the shared-memory pair and the engine-memory pair. Occupancy
|
|
81
|
+
* is judged on this ALREADY-MOUNTED roster (names + aliases). */
|
|
82
|
+
tools: AgentTool[];
|
|
83
|
+
/** borrowed-readonly — the frozen task-start tool face; only `exclude` is read (pair yield ①). */
|
|
84
|
+
toolFaceSnapshot: Pick<ToolFaceSnapshot, "exclude">;
|
|
85
|
+
/** borrowed-readonly — the once-per-session announcement ledger; only its deduplicated `onError`
|
|
86
|
+
* sink is invoked (a pair's mount shape is a session-level fact, announced once). */
|
|
87
|
+
onceLedger: AnnounceOnceSink;
|
|
88
|
+
/** borrowed-readonly — the memory phase's engine-pair ToolSpecs (present iff the pair may mount). */
|
|
89
|
+
memoryTools: ToolSpec[] | undefined;
|
|
90
|
+
/** borrowed-readonly — the memory phase's session seat; only `!== undefined` is read (the
|
|
91
|
+
* blocked-mount disclosure fires only when a session mounted). */
|
|
92
|
+
memoryEngineSession: Prepared["memoryEngineSession"];
|
|
93
|
+
/** borrowed-readonly — the engine pair's early conjuncts (computed before the memory phase). */
|
|
94
|
+
memorySearchToolsPlanned: boolean;
|
|
95
|
+
/** borrowed-readonly — the engine-pair name the exclusion valve removed, if any (disclosure text). */
|
|
96
|
+
memoryPairExcludedName: string | undefined;
|
|
97
|
+
/** borrowed-readonly — the engine-pair name a declared tool already occupies, if any (disclosure text). */
|
|
98
|
+
memoryPairOccupiedName: string | undefined;
|
|
99
|
+
/** borrowed-readonly — the durable-resume carrier; read for `!== undefined` (seedAnnounced) and
|
|
100
|
+
* `seed.announcedListings.skills` (the removal-to-zero projection's gate). */
|
|
101
|
+
resume: Pick<PrepareResume, "seed"> | undefined;
|
|
102
|
+
}
|
|
103
|
+
export interface PrepareProjectContextResult {
|
|
104
|
+
/** owned — the memory block with the project layer appended at the tail (unchanged when the seam is
|
|
105
|
+
* unwired or returns null/blank). The driver binds it under a NEW name; the defer-classification
|
|
106
|
+
* stretch may still strip the recall-discipline segment from it. */
|
|
107
|
+
memoryBlock: string | undefined;
|
|
108
|
+
/** owned — the snapshot's declared instruction sources (non-empty only), for the run loop's
|
|
109
|
+
* instructions_change lane (`Prepared.instructionSources`). */
|
|
110
|
+
instructionSources: ReadonlyArray<{
|
|
111
|
+
path: string;
|
|
112
|
+
contentHash: string | null;
|
|
113
|
+
}> | undefined;
|
|
114
|
+
/** owned — the RAW snapshot text (pre-compose) for the compaction lanes' instruction-file seat
|
|
115
|
+
* (`Prepared.projectInstructionContent`). */
|
|
116
|
+
projectInstructionContent: string | undefined;
|
|
117
|
+
/** owned — the normalized, load-gated skills (first-wins dedupe, name-sorted). Consumed inside this
|
|
118
|
+
* phase (tool + listing); exposed as the phase's own product. */
|
|
119
|
+
skillSpecs: ReturnType<typeof normalizeSkills>;
|
|
120
|
+
/** owned — whether THIS task carries a manifested skill or inherits a parent frame (the skill-scope
|
|
121
|
+
* policy's activation predicate). */
|
|
122
|
+
hasSkillManifest: boolean;
|
|
123
|
+
/** owned — the skills-listing projection the run loop's announce lane consumes (`Prepared.skillsListing`). */
|
|
124
|
+
skillsListing: Prepared["skillsListing"];
|
|
125
|
+
/** owned — whether the shared-memory pair mounted here (the support-name pre-check reads it). */
|
|
126
|
+
sharedMemoryPairMounted: boolean;
|
|
127
|
+
/** owned — whether the engine-memory pair mounted here (the support-name pre-check reads it). */
|
|
128
|
+
memoryEnginePairMounted: boolean;
|
|
129
|
+
}
|
|
130
|
+
/** The M9 phase body — prepareTask's project-context stretch, verbatim (see the module header). */
|
|
131
|
+
export declare function prepareProjectContext(input: PrepareProjectContextInput): Promise<PrepareProjectContextResult>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { PROJECT_CONTEXT_FRAMING } from "../../prompts/default.js";
|
|
2
|
+
import { MEMORY_ENGINE_TOOL_NAMES } from "../memory-engine/tools.js";
|
|
3
|
+
import { composeMemoryBlock } from "../memory.js";
|
|
4
|
+
import { createSharedMemoryTools } from "../shared-memory/tools.js";
|
|
5
|
+
import { SHARED_MEMORY_TOOL_NAMES } from "../shared-memory/types.js";
|
|
6
|
+
import { defineTool } from "../tools.js";
|
|
7
|
+
import { SKILL_CONTENT_MAX_CHARS, SKILL_TOOL_NAME, createSkillTool, normalizeSkills } from "./synthetic-tools.js";
|
|
8
|
+
export function hasConversationContent(branch) {
|
|
9
|
+
return branch.some((e) => e.type === "message" || e.type === "custom_message" || e.type === "compaction");
|
|
10
|
+
}
|
|
11
|
+
export async function prepareProjectContext(input) {
|
|
12
|
+
const { deps, spec, internals, session, sessionId, hostTaskId, taskRootFinal, handsEnabled, delegation, seedContextFiles, memoryBlockFromEngine, skillScope, tools, toolFaceSnapshot, onceLedger, memoryTools, memoryEngineSession, memorySearchToolsPlanned, memoryPairExcludedName, memoryPairOccupiedName, resume } = input;
|
|
13
|
+
let memoryBlock = memoryBlockFromEngine;
|
|
14
|
+
let instructionSources;
|
|
15
|
+
let projectInstructionContent;
|
|
16
|
+
if (deps.loadProjectMemory) {
|
|
17
|
+
let projectMemoryPhase = spec.sessionId ? "resume" : "fresh";
|
|
18
|
+
if (spec.sessionId) {
|
|
19
|
+
try {
|
|
20
|
+
const branch = await session.getBranch();
|
|
21
|
+
const hasConversation = hasConversationContent(branch);
|
|
22
|
+
if (!hasConversation)
|
|
23
|
+
projectMemoryPhase = "fresh";
|
|
24
|
+
else {
|
|
25
|
+
for (let i = branch.length - 1; i >= 0; i--) {
|
|
26
|
+
const e = branch[i];
|
|
27
|
+
if (e.type === "compaction") {
|
|
28
|
+
projectMemoryPhase = "post-compact";
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
if (e.type === "message" && e.message.role === "user")
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let loaded = null;
|
|
40
|
+
try {
|
|
41
|
+
loaded = await Promise.resolve(deps.loadProjectMemory({
|
|
42
|
+
cwd: taskRootFinal,
|
|
43
|
+
handsEnabled,
|
|
44
|
+
isSubagent: delegation.isNonForkChild,
|
|
45
|
+
...(internals?.agentName ? { agentName: internals.agentName } : {}),
|
|
46
|
+
sessionId,
|
|
47
|
+
phase: projectMemoryPhase,
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
|
|
52
|
+
}
|
|
53
|
+
const projectMem = loaded !== null && typeof loaded === "object" ? loaded.content : loaded;
|
|
54
|
+
const seededFiles = loaded !== null && typeof loaded === "object" ? loaded.seededFiles : undefined;
|
|
55
|
+
const declaredSources = loaded !== null && typeof loaded === "object" ? loaded.instructionSources : undefined;
|
|
56
|
+
if (declaredSources !== undefined && declaredSources.length > 0)
|
|
57
|
+
instructionSources = declaredSources;
|
|
58
|
+
if (seededFiles?.length && seedContextFiles) {
|
|
59
|
+
try {
|
|
60
|
+
await seedContextFiles(seededFiles);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
deps.onError?.(err instanceof Error ? err : new Error(String(err)), { phase: "config", sessionId });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (projectMem != null && projectMem.trim()) {
|
|
67
|
+
projectInstructionContent = projectMem;
|
|
68
|
+
const projectBlock = `${PROJECT_CONTEXT_FRAMING}\n\n${composeMemoryBlock(projectMem, "project")}`;
|
|
69
|
+
memoryBlock = memoryBlock ? `${memoryBlock}\n\n${projectBlock}` : projectBlock;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const declaredSkillRank = new Map();
|
|
73
|
+
for (const s of spec.skills ?? [])
|
|
74
|
+
if (!declaredSkillRank.has(s.name))
|
|
75
|
+
declaredSkillRank.set(s.name, declaredSkillRank.size);
|
|
76
|
+
const skillSpecs = normalizeSkills(spec.skills ?? []).filter((s) => {
|
|
77
|
+
if (s.content.length <= SKILL_CONTENT_MAX_CHARS)
|
|
78
|
+
return true;
|
|
79
|
+
deps.onError?.(new Error(`Skill "${s.name}" content is ${s.content.length} chars, over the ${SKILL_CONTENT_MAX_CHARS}-char load limit — skill not loaded (skills are never truncated; shrink the body or move material to attachments/files).`), { phase: "config", sessionId });
|
|
80
|
+
return false;
|
|
81
|
+
});
|
|
82
|
+
const inheritedFrames = internals?.inheritedManifestScope ?? [];
|
|
83
|
+
for (const frame of inheritedFrames) {
|
|
84
|
+
skillScope.push(frame);
|
|
85
|
+
}
|
|
86
|
+
const hasSkillManifest = skillSpecs.some((s) => s.manifest !== undefined) || inheritedFrames.length > 0;
|
|
87
|
+
if (skillSpecs.length > 0) {
|
|
88
|
+
if (tools.some((t) => t.name === SKILL_TOOL_NAME)) {
|
|
89
|
+
const e = new Error(`Tool name "${SKILL_TOOL_NAME}" is reserved when spec.skills is present.`);
|
|
90
|
+
e.code = "config.reserved_tool_name";
|
|
91
|
+
throw e;
|
|
92
|
+
}
|
|
93
|
+
tools.push(createSkillTool(skillSpecs, skillScope));
|
|
94
|
+
}
|
|
95
|
+
const sharedMemoryProvider = deps.sharedMemoryStores;
|
|
96
|
+
let sharedMemoryPairMounted = false;
|
|
97
|
+
if (sharedMemoryProvider !== undefined) {
|
|
98
|
+
const excluded = new Set(toolFaceSnapshot.exclude ?? []);
|
|
99
|
+
const mountedNameDomain = new Set();
|
|
100
|
+
for (const t of tools) {
|
|
101
|
+
mountedNameDomain.add(t.name);
|
|
102
|
+
for (const alias of t.aliases ?? [])
|
|
103
|
+
mountedNameDomain.add(alias);
|
|
104
|
+
}
|
|
105
|
+
const excludedName = SHARED_MEMORY_TOOL_NAMES.find((n) => excluded.has(n));
|
|
106
|
+
const occupiedName = SHARED_MEMORY_TOOL_NAMES.find((n) => mountedNameDomain.has(n));
|
|
107
|
+
if (excludedName !== undefined || occupiedName !== undefined) {
|
|
108
|
+
onceLedger.onError(new Error(`Shared memory tools ${SHARED_MEMORY_TOOL_NAMES.join("/")} were NOT mounted: ` +
|
|
109
|
+
(excludedName !== undefined
|
|
110
|
+
? `excludeTools removes "${excludedName}"`
|
|
111
|
+
: `this task already declares a tool named "${occupiedName}" (the built-in yields to it)`) +
|
|
112
|
+
" — the pair mounts together or not at all."), { phase: "config", sessionId, classification: "shared-memory-not-mounted" });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
tools.push(...createSharedMemoryTools({
|
|
116
|
+
provider: sharedMemoryProvider,
|
|
117
|
+
context: { sessionId, taskId: hostTaskId, ...(spec.principal !== undefined ? { principal: spec.principal } : {}) },
|
|
118
|
+
}).map((s) => defineTool(s)));
|
|
119
|
+
sharedMemoryPairMounted = true;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
let memoryEnginePairMounted = false;
|
|
123
|
+
if (memoryTools !== undefined && memoryTools.length > 0) {
|
|
124
|
+
tools.push(...memoryTools.map((s) => defineTool(s)));
|
|
125
|
+
memoryEnginePairMounted = true;
|
|
126
|
+
}
|
|
127
|
+
else if (memoryEngineSession !== undefined && !memorySearchToolsPlanned) {
|
|
128
|
+
onceLedger.onError(new Error(`Memory tools ${MEMORY_ENGINE_TOOL_NAMES.join("/")} were NOT mounted: ` +
|
|
129
|
+
(memoryPairExcludedName !== undefined
|
|
130
|
+
? `excludeTools removes "${memoryPairExcludedName}"`
|
|
131
|
+
: `this task already declares a tool named "${memoryPairOccupiedName}" (the built-in yields to it)`) +
|
|
132
|
+
" — these tools mount together or not at all."), { phase: "config", sessionId, classification: "memory-tools-not-mounted" });
|
|
133
|
+
}
|
|
134
|
+
const skillsListing = skillSpecs.length > 0
|
|
135
|
+
? {
|
|
136
|
+
entries: skillSpecs.map((s) => ({
|
|
137
|
+
name: s.name,
|
|
138
|
+
description: s.description,
|
|
139
|
+
...(s.files !== undefined ? { files: s.files.map((f) => ({ path: f.path })) } : {}),
|
|
140
|
+
...(declaredSkillRank.get(s.name) !== undefined ? { declaredRank: declaredSkillRank.get(s.name) } : {}),
|
|
141
|
+
})),
|
|
142
|
+
seedAnnounced: resume !== undefined || spec.sessionId !== undefined,
|
|
143
|
+
}
|
|
144
|
+
:
|
|
145
|
+
(resume?.seed.announcedListings?.skills?.length ?? 0) > 0 || spec.sessionId !== undefined
|
|
146
|
+
?
|
|
147
|
+
{ entries: [], seedAnnounced: true }
|
|
148
|
+
: undefined;
|
|
149
|
+
return { memoryBlock, instructionSources, projectInstructionContent, skillSpecs, hasSkillManifest, skillsListing, sharedMemoryPairMounted, memoryEnginePairMounted };
|
|
150
|
+
}
|