@deepstrike/sdk 0.2.17 → 0.2.19
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/harness/harness.js +10 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/kernel.d.ts +8 -15
- package/dist/runtime/kernel-step.js +3 -0
- package/dist/runtime/runner.d.ts +38 -0
- package/dist/runtime/runner.js +92 -9
- package/dist/skills/loader.d.ts +4 -0
- package/dist/skills/loader.js +9 -0
- package/dist/types/agent.d.ts +7 -0
- package/dist/types/agent.js +29 -0
- package/package.json +2 -2
package/dist/harness/harness.js
CHANGED
|
@@ -84,7 +84,6 @@ export class HarnessLoop {
|
|
|
84
84
|
}
|
|
85
85
|
async *stream(request) {
|
|
86
86
|
const kernel = getKernel();
|
|
87
|
-
const pipeline = new kernel.EvalPipeline({ extractSkillOnPass: true });
|
|
88
87
|
const criteria = request.criteria ?? [];
|
|
89
88
|
let currentGoal = request.goal;
|
|
90
89
|
let lastIterations = 0;
|
|
@@ -126,11 +125,10 @@ export class HarnessLoop {
|
|
|
126
125
|
}
|
|
127
126
|
}
|
|
128
127
|
yield { type: "supervising" };
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
// #6 (0.5.0): the eval/verdict compute is the kernel's stateless free functions (was the
|
|
129
|
+
// EvalPipeline state machine). Build the eval prompt, call the eval LLM, parse the verdict.
|
|
130
|
+
const evalMsgs = kernel.buildEvalMessages(request.goal, criteria, lastResult, attempt, true);
|
|
132
131
|
let evalText = "";
|
|
133
|
-
const evalMsgs = evalAction.messages ?? [];
|
|
134
132
|
const evalContext = {
|
|
135
133
|
systemText: evalMsgs.filter((m) => m.role === "system").map((m) => m.content).join("\n\n"),
|
|
136
134
|
turns: evalMsgs.filter((m) => m.role !== "system"),
|
|
@@ -139,18 +137,16 @@ export class HarnessLoop {
|
|
|
139
137
|
if (evt.type === "text_delta")
|
|
140
138
|
evalText += evt.delta;
|
|
141
139
|
}
|
|
142
|
-
const
|
|
143
|
-
if (doneAction.kind !== "done")
|
|
144
|
-
break;
|
|
140
|
+
const parsed = kernel.parseVerdict(evalText);
|
|
145
141
|
const verdict = {
|
|
146
|
-
passed:
|
|
147
|
-
overallScore:
|
|
148
|
-
feedback:
|
|
149
|
-
details:
|
|
142
|
+
passed: parsed.passed,
|
|
143
|
+
overallScore: parsed.overallScore,
|
|
144
|
+
feedback: parsed.feedback,
|
|
145
|
+
details: parsed.details ?? [],
|
|
150
146
|
};
|
|
151
147
|
if (verdict.passed) {
|
|
152
|
-
if (
|
|
153
|
-
const { name, description, whenToUse, content } =
|
|
148
|
+
if (parsed.skillCandidate && this.skillDir) {
|
|
149
|
+
const { name, description, whenToUse, content } = parsed.skillCandidate;
|
|
154
150
|
const fm = ["---", `name: ${name}`, `description: ${description}`,
|
|
155
151
|
whenToUse ? `when_to_use: ${whenToUse}` : null, "---", ""]
|
|
156
152
|
.filter(Boolean).join("\n");
|
|
@@ -162,7 +158,6 @@ export class HarnessLoop {
|
|
|
162
158
|
yield { type: "revising", verdict };
|
|
163
159
|
currentGoal = `${request.goal}\n\n[Attempt ${attempt} feedback: ${verdict.feedback}]`;
|
|
164
160
|
lastResult = "";
|
|
165
|
-
pipeline.reset();
|
|
166
161
|
}
|
|
167
162
|
yield { type: "max_attempts_reached" };
|
|
168
163
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -68,7 +68,7 @@ export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harne
|
|
|
68
68
|
export type { HarnessRequest, HarnessOutcome, HarnessLoopOptions, QualityGate } from "./harness/harness.js";
|
|
69
69
|
export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, ProviderReplay, RenderedContext, ReplayabilityAssessment, } from "./types.js";
|
|
70
70
|
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, WorkflowSpec, WorkflowNodeSpec, WorkflowTaskSpec, WorkflowSpawnInfo, } from "./types/agent.js";
|
|
71
|
-
export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, } from "./types/agent.js";
|
|
71
|
+
export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, genEval, } from "./types/agent.js";
|
|
72
72
|
export type { AcceptanceCriterion, VerificationContract, ContractCheckResult, } from "./collaboration/contract.js";
|
|
73
73
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
|
|
74
74
|
export { AgentPool } from "./collaboration/pool.js";
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ export { PermissionManager, PermissionMode } from "./safety/permissions.js";
|
|
|
46
46
|
export { Governance, governancePolicyToKernelEvent } from "./governance.js";
|
|
47
47
|
// ── Harness ────────────────────────────────────────────────────────────────
|
|
48
48
|
export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harness.js";
|
|
49
|
-
export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, } from "./types/agent.js";
|
|
49
|
+
export { agentIdentitySub, agentRunSpecToKernel, milestoneCheckFail, milestoneCheckPass, milestoneCheckResultToKernel, subAgentResultToKernel, workflowSpecToKernel, workflowNodeSpecToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, submitWorkflowNodesTool, startWorkflowTool, fanoutSynthesize, generateAndFilter, verifyRules, genEval, } from "./types/agent.js";
|
|
50
50
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
|
|
51
51
|
export { AgentPool } from "./collaboration/pool.js";
|
|
52
52
|
export { KERNEL_ROLE_MAP } from "./collaboration/pool.js";
|
package/dist/kernel.d.ts
CHANGED
|
@@ -77,13 +77,11 @@ interface NativeCriterion {
|
|
|
77
77
|
required: boolean;
|
|
78
78
|
weight?: number;
|
|
79
79
|
}
|
|
80
|
-
interface
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
feedback?: string;
|
|
86
|
-
details?: Array<{
|
|
80
|
+
export interface Verdict {
|
|
81
|
+
passed: boolean;
|
|
82
|
+
overallScore: number;
|
|
83
|
+
feedback: string;
|
|
84
|
+
details: Array<{
|
|
87
85
|
criterion: string;
|
|
88
86
|
passed: boolean;
|
|
89
87
|
score: number;
|
|
@@ -96,11 +94,6 @@ interface EvalPipelineAction {
|
|
|
96
94
|
content: string;
|
|
97
95
|
};
|
|
98
96
|
}
|
|
99
|
-
interface EvalPipelineInstance {
|
|
100
|
-
feedOutcome(goal: string, criteria: NativeCriterion[], result: string, attempt: number): EvalPipelineAction;
|
|
101
|
-
feedEvalResult(content: string): EvalPipelineAction;
|
|
102
|
-
reset(): void;
|
|
103
|
-
}
|
|
104
97
|
interface IdlePipelineAction {
|
|
105
98
|
kind: "synthesize_insights" | "commit_memories" | "noop" | "aborted";
|
|
106
99
|
messages?: Message[];
|
|
@@ -156,9 +149,9 @@ interface KernelModule {
|
|
|
156
149
|
timeoutMs?: bigint;
|
|
157
150
|
}) => KernelRuntimeInstance;
|
|
158
151
|
SignalRouter: new (maxQueueSize: number) => SignalRouterInstance;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
buildEvalMessages(goal: string, criteria: NativeCriterion[], result: string, attempt: number, extractSkillOnPass: boolean): Message[];
|
|
153
|
+
parseVerdict(content: string): Verdict;
|
|
154
|
+
verdictOutputSchema(extractSkillOnPass: boolean): string;
|
|
162
155
|
IdlePipeline: new (agentId: string) => IdlePipelineInstance;
|
|
163
156
|
}
|
|
164
157
|
export declare function getKernel(): KernelModule;
|
|
@@ -24,6 +24,9 @@ export function skillMetadataToKernel(skill) {
|
|
|
24
24
|
out.when_to_use = skill.whenToUse;
|
|
25
25
|
if (skill.effort !== undefined)
|
|
26
26
|
out.effort = skill.effort;
|
|
27
|
+
// P1-B: forward declared tool ids (additive; omitted when empty so existing skills' wire is unchanged).
|
|
28
|
+
if (skill.allowedTools?.length)
|
|
29
|
+
out.allowed_tools = skill.allowedTools;
|
|
27
30
|
return out;
|
|
28
31
|
}
|
|
29
32
|
export function messageToKernelMessage(message) {
|
package/dist/runtime/runner.d.ts
CHANGED
|
@@ -15,6 +15,30 @@ import { LargeResultSpool } from "./large-result-spool.js";
|
|
|
15
15
|
export interface SchedulerBudget {
|
|
16
16
|
maxWallMs?: number;
|
|
17
17
|
}
|
|
18
|
+
/** P0-C tool-gating telemetry: per-LLM-turn metrics, emitted via `RuntimeOptions.onTurnMetrics`.
|
|
19
|
+
* Pure observation — no behavior change. Feeds the go/no-go analysis for epoch skill gating (P1-B):
|
|
20
|
+
* - `toolsExposed` vs `toolsCalled` quantifies over-exposure.
|
|
21
|
+
* - `activeSkill` across consecutive turns yields the skill *dwell* `D` (how long a skill stays
|
|
22
|
+
* loaded) — the break-even input that decides whether dynamic gating beats the cache-bust cost.
|
|
23
|
+
* - `cacheReadTokens` / `cacheCreationTokens` give the prompt-cache hit baseline to compare against
|
|
24
|
+
* after B/D ship. */
|
|
25
|
+
export interface TurnMetrics {
|
|
26
|
+
/** 1-based kernel turn this LLM call belongs to. */
|
|
27
|
+
turn: number;
|
|
28
|
+
/** Number of tool schemas exposed to the model this turn (base + meta, after run-profile gating). */
|
|
29
|
+
toolsExposed: number;
|
|
30
|
+
/** Number of tool calls the model emitted this turn. */
|
|
31
|
+
toolsCalled: number;
|
|
32
|
+
/** The skill loaded and in effect going into this turn (the most recent `skill` tool call's name),
|
|
33
|
+
* or undefined if none is active. Consecutive equal values measure dwell. */
|
|
34
|
+
activeSkill?: string;
|
|
35
|
+
/** Full prompt size the provider reported (uncached + cache read + cache creation). */
|
|
36
|
+
inputTokens: number;
|
|
37
|
+
/** Tokens served from the prompt cache this turn (Anthropic `cache_read_input_tokens`). */
|
|
38
|
+
cacheReadTokens: number;
|
|
39
|
+
/** Tokens written to the prompt cache this turn (Anthropic `cache_creation_input_tokens`). */
|
|
40
|
+
cacheCreationTokens: number;
|
|
41
|
+
}
|
|
18
42
|
export interface RuntimeOptions {
|
|
19
43
|
provider: LLMProvider;
|
|
20
44
|
/** M4/G5: cumulative token cap for this run (the kernel's `max_total_tokens`). A workflow node's
|
|
@@ -98,6 +122,20 @@ export interface RuntimeOptions {
|
|
|
98
122
|
}) => Promise<MilestoneCheckResult> | MilestoneCheckResult;
|
|
99
123
|
/** Passed to kernel start_run for role/isolation metadata. */
|
|
100
124
|
runSpec?: AgentRunSpec;
|
|
125
|
+
/** P0-A tool gating: a static per-run tool profile — only these tool ids (plus the
|
|
126
|
+
* skill/memory/knowledge/update_plan meta-tools) are exposed to the model each turn.
|
|
127
|
+
* Sugar that lowers to the same `capability_filter` sub-agents use; byte-stable across
|
|
128
|
+
* the run, so it never busts the prompt-cache prefix. Augments `runSpec`'s filter when
|
|
129
|
+
* both are set; synthesizes a minimal run spec when `runSpec` is absent. Omitted/empty
|
|
130
|
+
* ⇒ all registered tools exposed (no gating). */
|
|
131
|
+
allowedToolIds?: string[];
|
|
132
|
+
/** P0-C: optional per-turn metrics sink for tool-gating telemetry (see `TurnMetrics`). Pure
|
|
133
|
+
* observation; invoked once per LLM turn. Never throws into the run loop (errors are swallowed). */
|
|
134
|
+
onTurnMetrics?: (metrics: TurnMetrics) => void;
|
|
135
|
+
/** P1-B/D stable-core: tool ids that stay exposed even when an active skill narrows the toolset
|
|
136
|
+
* (read/search/bash etc.). Empty/absent ⇒ skills narrow to exactly their declared `allowed_tools`
|
|
137
|
+
* + meta-tools. Opt-in: with no skill declaring `allowed_tools`, gating never engages. */
|
|
138
|
+
stableCoreToolIds?: string[];
|
|
101
139
|
/** Loaded via load_milestone_contract before run start. */
|
|
102
140
|
milestoneContract?: MilestoneContract;
|
|
103
141
|
/** Custom sub-agent host driver; defaults to SubAgentOrchestrator. */
|
package/dist/runtime/runner.js
CHANGED
|
@@ -819,15 +819,19 @@ export class RuntimeRunner {
|
|
|
819
819
|
if (this.opts.skillDir) {
|
|
820
820
|
const { scanSkillDir } = await import("../skills/loader.js");
|
|
821
821
|
const metas = await scanSkillDir(this.opts.skillDir);
|
|
822
|
+
// P1-B: pass the full SkillMetadata (incl. `allowedTools`) straight through — re-mapping it
|
|
823
|
+
// field-by-field previously dropped `allowedTools`.
|
|
822
824
|
kernelApply(runtime, this.pendingObservations, {
|
|
823
825
|
kind: "set_available_skills",
|
|
824
|
-
skills: metas.map(
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
826
|
+
skills: metas.map(m => skillMetadataToKernel(m)),
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
// P1-B/D: configure the stable-core tool ids (always exposed under skill gating). Empty/absent
|
|
830
|
+
// ⇒ skills narrow to exactly their declared tools + meta-tools.
|
|
831
|
+
if (this.opts.stableCoreToolIds?.length) {
|
|
832
|
+
kernelApply(runtime, this.pendingObservations, {
|
|
833
|
+
kind: "set_stable_core_tools",
|
|
834
|
+
tool_ids: this.opts.stableCoreToolIds,
|
|
831
835
|
});
|
|
832
836
|
}
|
|
833
837
|
if (this.opts.dreamStore && this.opts.agentId) {
|
|
@@ -876,14 +880,43 @@ export class RuntimeRunner {
|
|
|
876
880
|
kind: "preload_history",
|
|
877
881
|
messages: replayed.map(messageToKernelMessage),
|
|
878
882
|
});
|
|
883
|
+
// P1-B B3: rebuild active-skill gating after a wake by re-emitting SkillActivated for each
|
|
884
|
+
// `skill` tool call in the replayed history (active_skills is not snapshotted — graceful).
|
|
885
|
+
// The catalog (set_available_skills) was already fed above, so allowed_tools resolves.
|
|
886
|
+
for (const m of replayed) {
|
|
887
|
+
for (const tc of m.toolCalls ?? []) {
|
|
888
|
+
if (tc.name !== "skill")
|
|
889
|
+
continue;
|
|
890
|
+
try {
|
|
891
|
+
const name = JSON.parse(tc.arguments || "{}").name;
|
|
892
|
+
if (name)
|
|
893
|
+
kernelApply(runtime, this.pendingObservations, { kind: "skill_activated", name });
|
|
894
|
+
}
|
|
895
|
+
catch { /* malformed skill args — skip */ }
|
|
896
|
+
}
|
|
897
|
+
}
|
|
879
898
|
}
|
|
880
899
|
const sessionStart = Date.now();
|
|
881
900
|
const startPayload = {
|
|
882
901
|
kind: "start_run",
|
|
883
902
|
task: { goal, criteria },
|
|
884
903
|
};
|
|
885
|
-
|
|
886
|
-
|
|
904
|
+
// P0-A: lower an explicit `runSpec` and/or the `allowedToolIds` profile to the kernel's
|
|
905
|
+
// `capability_filter`. `allowedToolIds` augments an explicit spec's filter, else synthesizes
|
|
906
|
+
// a minimal top-level spec carrying just the filter (reuses the existing run_spec wire — no
|
|
907
|
+
// new ABI). Unset on both ⇒ no run_spec ⇒ no gating (铁律: no config = old behavior).
|
|
908
|
+
const allowedToolIds = this.opts.allowedToolIds;
|
|
909
|
+
const hasProfile = allowedToolIds !== undefined && allowedToolIds.length > 0;
|
|
910
|
+
if (this.opts.runSpec || hasProfile) {
|
|
911
|
+
const baseSpec = this.opts.runSpec ?? {
|
|
912
|
+
identity: { agentId: this.opts.agentId ?? "root", sessionId, isSubAgent: false },
|
|
913
|
+
role: "custom",
|
|
914
|
+
goal,
|
|
915
|
+
};
|
|
916
|
+
const spec = hasProfile
|
|
917
|
+
? { ...baseSpec, capabilityFilter: { ...baseSpec.capabilityFilter, allowedIds: allowedToolIds } }
|
|
918
|
+
: baseSpec;
|
|
919
|
+
startPayload.run_spec = agentRunSpecToKernel(spec);
|
|
887
920
|
}
|
|
888
921
|
const osProfile = assertNativeProfile(this.opts.osProfile ?? "native");
|
|
889
922
|
const attentionPolicy = this.opts.attentionPolicy ?? osProfile.attentionPolicy;
|
|
@@ -944,6 +977,9 @@ export class RuntimeRunner {
|
|
|
944
977
|
? kernelAction(runtime, this.pendingObservations, { kind: "resume" })
|
|
945
978
|
: kernelAction(runtime, this.pendingObservations, startPayload);
|
|
946
979
|
let hasAttemptedReactiveCompact = false;
|
|
980
|
+
// P0-C: the skill loaded and in effect going into the current turn (updated when the model's
|
|
981
|
+
// `skill` tool call resolves). Drives the per-turn `activeSkill` metric → dwell measurement.
|
|
982
|
+
let activeSkill;
|
|
947
983
|
while (!runtime.isTerminal()) {
|
|
948
984
|
// Page-in must run before appendObservations drains pending kernel observations.
|
|
949
985
|
if (action.kind === "execute_tool") {
|
|
@@ -985,6 +1021,8 @@ export class RuntimeRunner {
|
|
|
985
1021
|
let turnTokens = 0;
|
|
986
1022
|
let turnInputTokens = 0;
|
|
987
1023
|
let turnOutputTokens = 0;
|
|
1024
|
+
let turnCacheReadTokens = 0;
|
|
1025
|
+
let turnCacheCreationTokens = 0;
|
|
988
1026
|
let shouldRetry = false;
|
|
989
1027
|
const abortSignal = this.abortController?.signal;
|
|
990
1028
|
try {
|
|
@@ -999,6 +1037,9 @@ export class RuntimeRunner {
|
|
|
999
1037
|
turnTokens = usageEvt.totalTokens;
|
|
1000
1038
|
turnInputTokens = usageEvt.inputTokens ?? 0;
|
|
1001
1039
|
turnOutputTokens = usageEvt.outputTokens ?? 0;
|
|
1040
|
+
// P0-C: capture the prompt-cache split for the tool-gating hit-rate baseline.
|
|
1041
|
+
turnCacheReadTokens = usageEvt.cacheReadInputTokens ?? 0;
|
|
1042
|
+
turnCacheCreationTokens = usageEvt.cacheCreationInputTokens ?? 0;
|
|
1002
1043
|
continue;
|
|
1003
1044
|
}
|
|
1004
1045
|
yield evt;
|
|
@@ -1079,6 +1120,32 @@ export class RuntimeRunner {
|
|
|
1079
1120
|
toolCalls: finalToolCalls,
|
|
1080
1121
|
providerReplay,
|
|
1081
1122
|
}));
|
|
1123
|
+
// P0-C: emit per-turn tool-gating telemetry. `activeSkill` reflects the skill in effect
|
|
1124
|
+
// GOING INTO this turn; a `skill` call here only takes effect next turn, so emit first, then
|
|
1125
|
+
// advance. Wrapped so a faulty sink can never break the run (pure observation).
|
|
1126
|
+
if (this.opts.onTurnMetrics) {
|
|
1127
|
+
try {
|
|
1128
|
+
this.opts.onTurnMetrics({
|
|
1129
|
+
turn: runtime.turn(),
|
|
1130
|
+
toolsExposed: tools.length,
|
|
1131
|
+
toolsCalled: finalToolCalls.length,
|
|
1132
|
+
activeSkill,
|
|
1133
|
+
inputTokens: turnInputTokens,
|
|
1134
|
+
cacheReadTokens: turnCacheReadTokens,
|
|
1135
|
+
cacheCreationTokens: turnCacheCreationTokens,
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
catch { /* metrics must never break the run */ }
|
|
1139
|
+
}
|
|
1140
|
+
const skillCall = finalToolCalls.find(c => c.name === "skill");
|
|
1141
|
+
if (skillCall) {
|
|
1142
|
+
try {
|
|
1143
|
+
const name = JSON.parse(skillCall.arguments || "{}").name;
|
|
1144
|
+
if (name)
|
|
1145
|
+
activeSkill = name;
|
|
1146
|
+
}
|
|
1147
|
+
catch { /* malformed skill args — leave activeSkill unchanged */ }
|
|
1148
|
+
}
|
|
1082
1149
|
}
|
|
1083
1150
|
else if (action.kind === "execute_tool") {
|
|
1084
1151
|
const allCalls = action.calls;
|
|
@@ -1214,6 +1281,22 @@ export class RuntimeRunner {
|
|
|
1214
1281
|
this.pendingSpoolOutputs.set(call.id, { tool: call.name, output: result.output });
|
|
1215
1282
|
}
|
|
1216
1283
|
}
|
|
1284
|
+
// P1-B B3: a `skill` call that resolved successfully activates that skill in the kernel, so
|
|
1285
|
+
// the next `call_provider` narrows the toolset to its declared tools. Fed before `tool_results`
|
|
1286
|
+
// (which computes the next action). Errs-open: a failed/missing skill load doesn't activate.
|
|
1287
|
+
for (const call of allCalls) {
|
|
1288
|
+
if (call.name !== "skill")
|
|
1289
|
+
continue;
|
|
1290
|
+
const res = toolResults.find(r => r.callId === call.id);
|
|
1291
|
+
if (!res || res.isError)
|
|
1292
|
+
continue;
|
|
1293
|
+
try {
|
|
1294
|
+
const name = JSON.parse(call.arguments || "{}").name;
|
|
1295
|
+
if (name)
|
|
1296
|
+
kernelApply(runtime, this.pendingObservations, { kind: "skill_activated", name });
|
|
1297
|
+
}
|
|
1298
|
+
catch { /* malformed skill args — skip activation */ }
|
|
1299
|
+
}
|
|
1217
1300
|
action = kernelAction(runtime, this.pendingObservations, {
|
|
1218
1301
|
kind: "tool_results",
|
|
1219
1302
|
results: toolResults.map(toolResultToKernel),
|
package/dist/skills/loader.d.ts
CHANGED
|
@@ -4,6 +4,10 @@ export interface SkillMetadata {
|
|
|
4
4
|
whenToUse?: string;
|
|
5
5
|
effort?: number;
|
|
6
6
|
estimatedTokens?: number;
|
|
7
|
+
/** P1-B tool gating: tool ids this skill needs. When the skill is active, the kernel narrows the
|
|
8
|
+
* exposed toolset to `stable-core ∪ allowedTools`. Parsed from `allowed_tools:` frontmatter
|
|
9
|
+
* (comma-separated or `[a, b]`). Absent ⇒ the skill does not narrow (back-compat). */
|
|
10
|
+
allowedTools?: string[];
|
|
7
11
|
}
|
|
8
12
|
/** Read one skill file and return its body (frontmatter stripped). */
|
|
9
13
|
export declare function readSkillFile(skillDir: string, name: string): Promise<string | null>;
|
package/dist/skills/loader.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { readFile, readdir } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
|
+
/** Parse a frontmatter tool list: `read, write` or `[read, write]` → ["read","write"]. */
|
|
4
|
+
function parseToolList(v) {
|
|
5
|
+
if (v == null || v === "")
|
|
6
|
+
return undefined;
|
|
7
|
+
const ids = String(v).trim().replace(/^\[|\]$/g, "").split(",")
|
|
8
|
+
.map(x => x.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
9
|
+
return ids.length ? ids : undefined;
|
|
10
|
+
}
|
|
3
11
|
function parseFrontmatter(content) {
|
|
4
12
|
const match = content.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
|
5
13
|
if (!match)
|
|
@@ -38,6 +46,7 @@ export async function scanSkillDir(skillDir) {
|
|
|
38
46
|
whenToUse: meta.when_to_use ? String(meta.when_to_use) : undefined,
|
|
39
47
|
effort: meta.effort ? Number(meta.effort) : undefined,
|
|
40
48
|
estimatedTokens: meta.estimated_tokens ? Number(meta.estimated_tokens) : undefined,
|
|
49
|
+
allowedTools: parseToolList(meta.allowed_tools),
|
|
41
50
|
});
|
|
42
51
|
}
|
|
43
52
|
return results;
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -225,6 +225,13 @@ export declare function workflowNodeToManifest(node: WorkflowSpawnInfo, parentSe
|
|
|
225
225
|
export declare function fanoutSynthesize(workers: WorkflowTaskSpec[], synthesize: WorkflowTaskSpec): WorkflowSpec;
|
|
226
226
|
/** N parallel Implement generators feeding a single Verify filter/dedupe step (barrier). */
|
|
227
227
|
export declare function generateAndFilter(generators: WorkflowTaskSpec[], filter: WorkflowTaskSpec): WorkflowSpec;
|
|
228
|
+
/**
|
|
229
|
+
* Generate→evaluate quality gate (the EvalPipeline successor, #6): a `loop` worker node (re-run up
|
|
230
|
+
* to `maxIters`, stopping early on a `loop_continue=false` self-signal) + a bias-resistant `verify`
|
|
231
|
+
* eval node gated on it, carrying the kernel's verdict `outputSchema`. Mirrors the kernel `gen_eval`
|
|
232
|
+
* template. For the iterative retry-with-feedback variant, drive it with `HarnessLoop`.
|
|
233
|
+
*/
|
|
234
|
+
export declare function genEval(worker: WorkflowTaskSpec, evaluate: WorkflowTaskSpec, maxIters?: number, extractSkillOnPass?: boolean): WorkflowSpec;
|
|
228
235
|
/**
|
|
229
236
|
* One fresh-context verifier per rule/claim (parallel) + optional skeptic that depends on all and
|
|
230
237
|
* re-checks flags. Verifiers run read-only with no inherited author context (bias-resistant).
|
package/dist/types/agent.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getKernel } from "../kernel.js";
|
|
1
2
|
/** Map kernel spawn observation → host manifest. */
|
|
2
3
|
export function spawnObservationToManifest(obs, spec, parentSessionId) {
|
|
3
4
|
const o = obs;
|
|
@@ -409,6 +410,34 @@ export function generateAndFilter(generators, filter) {
|
|
|
409
410
|
});
|
|
410
411
|
return { nodes };
|
|
411
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Generate→evaluate quality gate (the EvalPipeline successor, #6): a `loop` worker node (re-run up
|
|
415
|
+
* to `maxIters`, stopping early on a `loop_continue=false` self-signal) + a bias-resistant `verify`
|
|
416
|
+
* eval node gated on it, carrying the kernel's verdict `outputSchema`. Mirrors the kernel `gen_eval`
|
|
417
|
+
* template. For the iterative retry-with-feedback variant, drive it with `HarnessLoop`.
|
|
418
|
+
*/
|
|
419
|
+
export function genEval(worker, evaluate, maxIters = 3, extractSkillOnPass = true) {
|
|
420
|
+
const schema = JSON.parse(getKernel().verdictOutputSchema(extractSkillOnPass));
|
|
421
|
+
return {
|
|
422
|
+
nodes: [
|
|
423
|
+
{
|
|
424
|
+
task: asTask(worker),
|
|
425
|
+
role: "implement",
|
|
426
|
+
isolation: "worktree",
|
|
427
|
+
contextInheritance: "full",
|
|
428
|
+
loop: { maxIters: Math.max(1, maxIters) },
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
task: asTask(evaluate),
|
|
432
|
+
role: "verify",
|
|
433
|
+
isolation: "read_only",
|
|
434
|
+
contextInheritance: "none",
|
|
435
|
+
dependsOn: [0],
|
|
436
|
+
outputSchema: schema,
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
};
|
|
440
|
+
}
|
|
412
441
|
/**
|
|
413
442
|
* One fresh-context verifier per rule/claim (parallel) + optional skeptic that depends on all and
|
|
414
443
|
* re-checks flags. Verifiers run read-only with no inherited author context (bias-resistant).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepstrike/sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.19",
|
|
4
4
|
"description": "DeepStrike Node.js SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@anthropic-ai/sdk": "^0.99.0",
|
|
23
|
-
"@deepstrike/core": "0.2.
|
|
23
|
+
"@deepstrike/core": "0.2.19",
|
|
24
24
|
"@google/generative-ai": "^0.24.1",
|
|
25
25
|
"openai": "^5.23.2"
|
|
26
26
|
},
|