@namzu/sdk 5.1.0 → 5.2.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 +361 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts +2 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js +76 -0
- package/dist/agents/__tests__/run-agent-forwarding.test.js.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts +2 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.d.ts.map +1 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js +50 -0
- package/dist/agents/__tests__/run-completed-stop-reason.test.js.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +4 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/runAgent.d.ts +34 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +5 -3
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/config/runtime.d.ts +30 -30
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts +2 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.d.ts.map +1 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js +54 -0
- package/dist/constants/tools/__tests__/dangerous-patterns.test.js.map +1 -0
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +28 -1
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/contracts/a2a.d.ts +44 -44
- package/dist/directory/__tests__/derive.test.d.ts +2 -0
- package/dist/directory/__tests__/derive.test.d.ts.map +1 -0
- package/dist/directory/__tests__/derive.test.js +111 -0
- package/dist/directory/__tests__/derive.test.js.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts +2 -0
- package/dist/directory/__tests__/load-diagnostics.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-diagnostics.test.js +106 -0
- package/dist/directory/__tests__/load-diagnostics.test.js.map +1 -0
- package/dist/directory/__tests__/load-directory.test.d.ts +2 -0
- package/dist/directory/__tests__/load-directory.test.d.ts.map +1 -0
- package/dist/directory/__tests__/load-directory.test.js +196 -0
- package/dist/directory/__tests__/load-directory.test.js.map +1 -0
- package/dist/directory/__tests__/subagents.test.d.ts +2 -0
- package/dist/directory/__tests__/subagents.test.d.ts.map +1 -0
- package/dist/directory/__tests__/subagents.test.js +117 -0
- package/dist/directory/__tests__/subagents.test.js.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts +2 -0
- package/dist/directory/__tests__/supervisor-budget.test.d.ts.map +1 -0
- package/dist/directory/__tests__/supervisor-budget.test.js +97 -0
- package/dist/directory/__tests__/supervisor-budget.test.js.map +1 -0
- package/dist/directory/derive-supervisor.d.ts +58 -0
- package/dist/directory/derive-supervisor.d.ts.map +1 -0
- package/dist/directory/derive-supervisor.js +88 -0
- package/dist/directory/derive-supervisor.js.map +1 -0
- package/dist/directory/derive.d.ts +12 -0
- package/dist/directory/derive.d.ts.map +1 -0
- package/dist/directory/derive.js +58 -0
- package/dist/directory/derive.js.map +1 -0
- package/dist/directory/index.d.ts +7 -0
- package/dist/directory/index.d.ts.map +1 -0
- package/dist/directory/index.js +5 -0
- package/dist/directory/index.js.map +1 -0
- package/dist/directory/load.d.ts +14 -0
- package/dist/directory/load.d.ts.map +1 -0
- package/dist/directory/load.js +488 -0
- package/dist/directory/load.js.map +1 -0
- package/dist/directory/scan.d.ts +36 -0
- package/dist/directory/scan.d.ts.map +1 -0
- package/dist/directory/scan.js +136 -0
- package/dist/directory/scan.js.map +1 -0
- package/dist/directory/types.d.ts +215 -0
- package/dist/directory/types.d.ts.map +1 -0
- package/dist/directory/types.js +8 -0
- package/dist/directory/types.js.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts +2 -0
- package/dist/plugin/__tests__/path-containment.test.d.ts.map +1 -0
- package/dist/plugin/__tests__/path-containment.test.js +91 -0
- package/dist/plugin/__tests__/path-containment.test.js.map +1 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +3 -3
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +12 -2
- package/dist/plugin/loader.js.map +1 -1
- package/dist/provider/__tests__/model-version.test.d.ts +2 -0
- package/dist/provider/__tests__/model-version.test.d.ts.map +1 -0
- package/dist/provider/__tests__/model-version.test.js +80 -0
- package/dist/provider/__tests__/model-version.test.js.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts +2 -0
- package/dist/provider/__tests__/strict-schema.test.d.ts.map +1 -0
- package/dist/provider/__tests__/strict-schema.test.js +109 -0
- package/dist/provider/__tests__/strict-schema.test.js.map +1 -0
- package/dist/provider/model-version.d.ts +60 -0
- package/dist/provider/model-version.d.ts.map +1 -0
- package/dist/provider/model-version.js +64 -0
- package/dist/provider/model-version.js.map +1 -0
- package/dist/provider/strict-schema.d.ts +49 -0
- package/dist/provider/strict-schema.d.ts.map +1 -0
- package/dist/provider/strict-schema.js +112 -0
- package/dist/provider/strict-schema.js.map +1 -0
- package/dist/public-runtime.d.ts +6 -1
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +21 -1
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts +2 -0
- package/dist/registry/tool/__tests__/strict-registration.test.d.ts.map +1 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js +82 -0
- package/dist/registry/tool/__tests__/strict-registration.test.js.map +1 -0
- package/dist/registry/tool/execute.d.ts.map +1 -1
- package/dist/registry/tool/execute.js +16 -0
- package/dist/registry/tool/execute.js.map +1 -1
- package/dist/runtime/query/result.d.ts.map +1 -1
- package/dist/runtime/query/result.js +5 -0
- package/dist/runtime/query/result.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js +7 -1
- package/dist/tools/builtins/__tests__/edit-insert-reachable.test.js.map +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js +1 -1
- package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +20 -2
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/types/plugin/index.d.ts +4 -4
- package/dist/types/run/events.d.ts +17 -2
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/events.js.map +1 -1
- package/dist/types/verification/index.d.ts +6 -6
- package/package.json +1 -1
- package/src/agents/__tests__/run-agent-forwarding.test.ts +85 -0
- package/src/agents/__tests__/run-completed-stop-reason.test.ts +59 -0
- package/src/agents/index.ts +8 -0
- package/src/agents/runAgent.ts +30 -4
- package/src/constants/tools/__tests__/dangerous-patterns.test.ts +62 -0
- package/src/constants/tools/index.ts +28 -1
- package/src/directory/__tests__/derive.test.ts +135 -0
- package/src/directory/__tests__/load-diagnostics.test.ts +126 -0
- package/src/directory/__tests__/load-directory.test.ts +243 -0
- package/src/directory/__tests__/subagents.test.ts +155 -0
- package/src/directory/__tests__/supervisor-budget.test.ts +117 -0
- package/src/directory/derive-supervisor.ts +149 -0
- package/src/directory/derive.ts +70 -0
- package/src/directory/index.ts +27 -0
- package/src/directory/load.ts +556 -0
- package/src/directory/scan.ts +163 -0
- package/src/directory/types.ts +254 -0
- package/src/plugin/__tests__/path-containment.test.ts +107 -0
- package/src/plugin/lifecycle.ts +3 -3
- package/src/plugin/loader.ts +12 -2
- package/src/provider/__tests__/model-version.test.ts +93 -0
- package/src/provider/__tests__/strict-schema.test.ts +133 -0
- package/src/provider/model-version.ts +98 -0
- package/src/provider/strict-schema.ts +125 -0
- package/src/public-runtime.ts +31 -0
- package/src/public-types.ts +8 -0
- package/src/registry/tool/__tests__/strict-registration.test.ts +115 -0
- package/src/registry/tool/execute.ts +16 -0
- package/src/runtime/query/result.ts +5 -0
- package/src/tools/builtins/__tests__/edit-insert-reachable.test.ts +8 -2
- package/src/tools/builtins/__tests__/edit.test.ts +1 -1
- package/src/tools/builtins/edit.ts +20 -2
- package/src/types/run/events.ts +15 -2
|
@@ -177,11 +177,11 @@ export declare const PluginManifestSchema: z.ZodObject<{
|
|
|
177
177
|
personas: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
178
178
|
}, "strip", z.ZodTypeAny, {
|
|
179
179
|
name: string;
|
|
180
|
-
version: string;
|
|
181
180
|
description: string;
|
|
182
|
-
|
|
181
|
+
version: string;
|
|
183
182
|
tools?: string[] | undefined;
|
|
184
183
|
skills?: string[] | undefined;
|
|
184
|
+
author?: string | undefined;
|
|
185
185
|
hooks?: string[] | undefined;
|
|
186
186
|
mcpServers?: {
|
|
187
187
|
name: string;
|
|
@@ -193,11 +193,11 @@ export declare const PluginManifestSchema: z.ZodObject<{
|
|
|
193
193
|
personas?: string[] | undefined;
|
|
194
194
|
}, {
|
|
195
195
|
name: string;
|
|
196
|
-
version: string;
|
|
197
196
|
description: string;
|
|
198
|
-
|
|
197
|
+
version: string;
|
|
199
198
|
tools?: string[] | undefined;
|
|
200
199
|
skills?: string[] | undefined;
|
|
200
|
+
author?: string | undefined;
|
|
201
201
|
hooks?: string[] | undefined;
|
|
202
202
|
mcpServers?: {
|
|
203
203
|
name: string;
|
|
@@ -7,7 +7,7 @@ import type { PlanStep } from '../plan/index.js';
|
|
|
7
7
|
import type { PluginHookEvent, PluginHookResult } from '../plugin/index.js';
|
|
8
8
|
import type { TaskStatus } from '../task/index.js';
|
|
9
9
|
import type { Lineage } from './lineage.js';
|
|
10
|
-
import type { MessageStopReason } from './stop-reason.js';
|
|
10
|
+
import type { MessageStopReason, StopReason } from './stop-reason.js';
|
|
11
11
|
import type { SubsessionIdledEvent, SubsessionMessagedEvent, SubsessionSpawnedEvent } from './subsession-events.js';
|
|
12
12
|
export type { MessageStopReason, StopReason } from './stop-reason.js';
|
|
13
13
|
/**
|
|
@@ -233,10 +233,25 @@ type CoreRunEvent = {
|
|
|
233
233
|
action: 'block' | 'rewrite';
|
|
234
234
|
guardrail?: string;
|
|
235
235
|
reason?: string;
|
|
236
|
-
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* The run reached its end without throwing.
|
|
239
|
+
*
|
|
240
|
+
* `completed` is not `succeeded`. A run stopped by its token budget, its
|
|
241
|
+
* timeout, its iteration cap, a cancellation or a blocking output guardrail
|
|
242
|
+
* all arrive here — `run_failed` is emitted only from the throw path — so a
|
|
243
|
+
* consumer that treated this event as success reported one for a run whose
|
|
244
|
+
* answer was refused. Measured: `max_iterations` produces
|
|
245
|
+
* `status: 'completed'` with `result` holding whatever partial text existed.
|
|
246
|
+
*
|
|
247
|
+
* `stopReason` is what separates them, and it is on the event because the
|
|
248
|
+
* alternative is asking every consumer to hold the `Run` as well.
|
|
249
|
+
*/
|
|
250
|
+
| {
|
|
237
251
|
type: 'run_completed';
|
|
238
252
|
runId: RunId;
|
|
239
253
|
result: string;
|
|
254
|
+
stopReason?: StopReason;
|
|
240
255
|
}
|
|
241
256
|
/**
|
|
242
257
|
* The run failed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/types/run/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,KAAK,EACX,UAAU,EACV,SAAS,EACT,MAAM,EACN,QAAQ,EACR,KAAK,EACL,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/types/run/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,KAAK,EACX,UAAU,EACV,SAAS,EACT,MAAM,EACN,QAAQ,EACR,KAAK,EACL,SAAS,EACT,MAAM,EACN,SAAS,EACT,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAC3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,KAAK,EACX,oBAAoB,EACpB,uBAAuB,EACvB,sBAAsB,EACtB,MAAM,wBAAwB,CAAA;AAE/B,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAErE;;;;;;;;GAQG;AACH,UAAU,gBAAgB;IACzB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,KAAK,YAAY,GACd;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9D;IACA,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,OAAO,CAAA;CACpB;AACH;;;;;;;;GAQG;GACD;IACA,IAAI,EAAE,sBAAsB,CAAA;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,0CAA0C;IAC1C,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;IACrB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,UAAU,EAAE,UAAU,GAAG,UAAU,CAAA;IACnC,uEAAuE;IACvE,mBAAmB,EAAE,MAAM,CAAA;IAC3B,YAAY,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS,CAAA;IAClD;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;CAC9B,GACD;IACA,IAAI,EAAE,gBAAgB,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;CACb;AACH;;;;;;;;;;;;;GAaG;GACD;IACA,IAAI,EAAE,eAAe,CAAA;IACrB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAA;IACf,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAChB;AACH;;;;;;;;;;;;;GAaG;GACD;IACA,IAAI,EAAE,gBAAgB,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAA;CACtB,GACD;IACA,IAAI,EAAE,gBAAgB,CAAA;IACtB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,oEAAoE;IACpE,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,8DAA8D;IAC9D,eAAe,CAAC,EAAE,MAAM,CAAA;CACvB;AACH;;;;;;;;GAQG;GACD;IACA,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,YAAY,CAAA;IAC1B,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACf;AACH;;;;;;GAMG;GACD;IACA,IAAI,EAAE,wBAAwB,CAAA;IAC9B,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,YAAY,CAAA;IAC1B;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;CAChB,GACD;IACA,IAAI,EAAE,uBAAuB,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,eAAe,EAAE,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAChB,GACD;IACA,IAAI,EAAE,uBAAuB,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,UAAU,GAAG,UAAU,GAAG,UAAU,CAAA;CAC7C,GACD;IACA,IAAI,EAAE,oBAAoB,CAAA;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,YAAY,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;CAChB,GACD;IACA,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,YAAY,EAAE,YAAY,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;CACb,GACD;IACA,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,gBAAgB,EAAE,YAAY,CAAA;CAC7B;AACH;;;;;;GAMG;GACD;IACA,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IACzB,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;CACd;AACH;;;;;;;;;;;;GAYG;GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE;AAClF;;;;;;;;;;;;;;;GAeG;GACD;IACA,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,sBAAsB,EAAE,iBAAiB,CAAA;IAChE;;;;;;OAMG;IACH,WAAW,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;CAC1D,GAOD;IACA,IAAI,EAAE,oBAAoB,CAAA;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;CACd,GACD;IACA,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,KAAK,CAAA;IACZ,KAAK,EAAE,UAAU,CAAA;IACjB,IAAI,EAAE,QAAQ,CAAA;CACb,GACD;IACA,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,UAAU,CAAA;IACtB,YAAY,EAAE,YAAY,CAAA;IAC1B,WAAW,EAAE,MAAM,CAAA;CAClB,GACD;IACA,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,cAAc,CAAA;IACtB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACb,GACD;IACA,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;CACf,GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IACA,IAAI,EAAE,eAAe,CAAA;IACrB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CACd,GACD;IACA,IAAI,EAAE,mBAAmB,CAAA;IACzB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA;CACzB,GACD;IACA,IAAI,EAAE,eAAe,CAAA;IACrB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;CACZ,GACD;IACA,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,eAAe,CAAA;CACtB,GACD;IACA,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACZ,GACD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxD;IACA,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,UAAU,CAAA;CACjB,GACD;IACA,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACb,GACD;IACA,IAAI,EAAE,uBAAuB,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,eAAe,CAAA;CACzB,GACD;IACA,IAAI,EAAE,uBAAuB,CAAA;IAC7B,KAAK,EAAE,KAAK,CAAA;IACZ,QAAQ,EAAE,QAAQ,CAAA;IAClB,SAAS,EAAE,eAAe,CAAA;IAC1B,MAAM,EAAE,gBAAgB,CAAA;CACvB,GACD;IACA,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CAClB,GACD;IACA,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACjB,GACD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,KAAK,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GASjE;IACA,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;CACnB;AACH;;;;;;GAMG;GACD;IACA,IAAI,EAAE,mBAAmB,CAAA;IACzB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,UAAU,GAAG,mBAAmB,CAAA;CAC9C;AACH,uEAAuE;GACrE;IACA,IAAI,EAAE,iBAAiB,CAAA;IACvB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;CACX,GACD;IACA,IAAI,EAAE,qBAAqB,CAAA;IAC3B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAA;CACd,GACD;IACA,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;CACX,GACD;IACA,IAAI,EAAE,mBAAmB,CAAA;IACzB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,iBAAiB,CAAA;IAC7B,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACf,GACD;IACA,IAAI,EAAE,oBAAoB,CAAA;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,SAAS,CAAA;IACpB,SAAS,EAAE,SAAS,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACf,GACD;IACA,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CAClB,GACD;IACA,IAAI,EAAE,sBAAsB,CAAA;IAC5B,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,SAAS,CAAA;IACpB,KAAK,EAAE,OAAO,CAAA;IACd;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAEJ;;;;;;;;GAQG;AACH,MAAM,MAAM,QAAQ,GACjB,CAAC,YAAY,GAAG,gBAAgB,CAAC,GACjC,sBAAsB,GACtB,uBAAuB,GACvB,oBAAoB,CAAA;AAEvB,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AA8BxE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAEzD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/types/run/events.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/types/run/events.ts"],"names":[],"mappings":"AA8hBA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,qBAAqB,GAAkC,IAAI,GAAG,CAAmB;IACtF,YAAY;IACZ,kBAAkB;IAClB,mEAAmE;IACnE,6CAA6C;IAC7C,iBAAiB;IACjB,sEAAsE;IACtE,uEAAuE;IACvE,oCAAoC;IACpC,eAAe;CACf,CAAC,CAAA;AAEF,MAAM,UAAU,gBAAgB,CAAC,KAAe;IAC/C,OAAO,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;AAC7C,CAAC"}
|
|
@@ -73,13 +73,13 @@ export declare const VerificationRuleSchema: z.ZodDiscriminatedUnion<"type", [z.
|
|
|
73
73
|
decision: z.ZodEnum<["allow", "deny"]>;
|
|
74
74
|
}, "strip", z.ZodTypeAny, {
|
|
75
75
|
type: "custom_pattern";
|
|
76
|
-
pattern: string;
|
|
77
76
|
target: "name" | "args" | "both";
|
|
77
|
+
pattern: string;
|
|
78
78
|
decision: "deny" | "allow";
|
|
79
79
|
}, {
|
|
80
80
|
type: "custom_pattern";
|
|
81
|
-
pattern: string;
|
|
82
81
|
target: "name" | "args" | "both";
|
|
82
|
+
pattern: string;
|
|
83
83
|
decision: "deny" | "allow";
|
|
84
84
|
}>, z.ZodObject<{
|
|
85
85
|
type: z.ZodLiteral<"allow_by_tier">;
|
|
@@ -139,13 +139,13 @@ export declare const VerificationGateConfigSchema: z.ZodObject<{
|
|
|
139
139
|
decision: z.ZodEnum<["allow", "deny"]>;
|
|
140
140
|
}, "strip", z.ZodTypeAny, {
|
|
141
141
|
type: "custom_pattern";
|
|
142
|
-
pattern: string;
|
|
143
142
|
target: "name" | "args" | "both";
|
|
143
|
+
pattern: string;
|
|
144
144
|
decision: "deny" | "allow";
|
|
145
145
|
}, {
|
|
146
146
|
type: "custom_pattern";
|
|
147
|
-
pattern: string;
|
|
148
147
|
target: "name" | "args" | "both";
|
|
148
|
+
pattern: string;
|
|
149
149
|
decision: "deny" | "allow";
|
|
150
150
|
}>, z.ZodObject<{
|
|
151
151
|
type: z.ZodLiteral<"allow_by_tier">;
|
|
@@ -177,8 +177,8 @@ export declare const VerificationGateConfigSchema: z.ZodObject<{
|
|
|
177
177
|
toolNames: string[];
|
|
178
178
|
} | {
|
|
179
179
|
type: "custom_pattern";
|
|
180
|
-
pattern: string;
|
|
181
180
|
target: "name" | "args" | "both";
|
|
181
|
+
pattern: string;
|
|
182
182
|
decision: "deny" | "allow";
|
|
183
183
|
} | {
|
|
184
184
|
type: "allow_by_tier";
|
|
@@ -204,8 +204,8 @@ export declare const VerificationGateConfigSchema: z.ZodObject<{
|
|
|
204
204
|
toolNames: string[];
|
|
205
205
|
} | {
|
|
206
206
|
type: "custom_pattern";
|
|
207
|
-
pattern: string;
|
|
208
207
|
target: "name" | "args" | "both";
|
|
208
|
+
pattern: string;
|
|
209
209
|
decision: "deny" | "allow";
|
|
210
210
|
} | {
|
|
211
211
|
type: "allow_by_tier";
|
package/package.json
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import { MockLLMProvider, registerMock } from '../../provider/index.js'
|
|
5
|
+
import { ToolRegistry } from '../../registry/index.js'
|
|
6
|
+
import { runAgent } from '../runAgent.js'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The `drainQuery` call in `runAgent` was written `as never`.
|
|
10
|
+
*
|
|
11
|
+
* That cast was not load-bearing — removing it typechecks clean — but while it
|
|
12
|
+
* was there the kernel seam was unchecked in both directions: a field the
|
|
13
|
+
* kernel accepts and this door forgot to forward produced no error, and neither
|
|
14
|
+
* did a field spelled wrong. Two were already missing when it was removed.
|
|
15
|
+
*
|
|
16
|
+
* `skills` is the one with a caller in this repo. `@namzu/project` reads a
|
|
17
|
+
* whole `skills/` directory, put them on the options, and every one was dropped
|
|
18
|
+
* on the floor — the run was assembled without them and said nothing. These
|
|
19
|
+
* pin the forwarding rather than the cast, because the cast can come back and
|
|
20
|
+
* a test that only asserted its absence would not notice.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
registerMock()
|
|
24
|
+
|
|
25
|
+
describe('runAgent forwards what the kernel takes', () => {
|
|
26
|
+
it('puts skills in front of the model', async () => {
|
|
27
|
+
const provider = new MockLLMProvider({ turns: [{ text: 'ok' }] })
|
|
28
|
+
|
|
29
|
+
await runAgent({
|
|
30
|
+
provider,
|
|
31
|
+
model: 'mock-model',
|
|
32
|
+
prompt: 'plan something',
|
|
33
|
+
skills: [
|
|
34
|
+
{
|
|
35
|
+
metadata: { name: 'plan-a-trip', description: 'Plan a trip end to end' },
|
|
36
|
+
body: 'Ask for dates first.',
|
|
37
|
+
dirPath: '/tmp/skills/plan-a-trip',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
// Serialized rather than reached into: the prompt builder decides where a
|
|
43
|
+
// skill lands, and pinning that path here would make this test fail on a
|
|
44
|
+
// refactor that kept the behaviour. What matters is that it arrived.
|
|
45
|
+
expect(JSON.stringify(provider.requests[0])).toContain('plan-a-trip')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it('forwards the verification gate, so a denied tool does not run', async () => {
|
|
49
|
+
// The first version of this test asserted `run.status === 'completed'`
|
|
50
|
+
// with the gate set. It passed with the forwarding deleted — a run with
|
|
51
|
+
// no gate completes too — so it proved nothing. A gate is only observable
|
|
52
|
+
// through a call it stops, which means the assertion has to be about
|
|
53
|
+
// whether the tool body ran.
|
|
54
|
+
let ran = false
|
|
55
|
+
|
|
56
|
+
const tools = new ToolRegistry()
|
|
57
|
+
tools.register({
|
|
58
|
+
name: 'delete_everything',
|
|
59
|
+
description: 'Deletes everything.',
|
|
60
|
+
inputSchema: z.object({}),
|
|
61
|
+
execute: async () => {
|
|
62
|
+
ran = true
|
|
63
|
+
return { success: true, output: 'deleted' }
|
|
64
|
+
},
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
await runAgent({
|
|
68
|
+
provider: new MockLLMProvider({
|
|
69
|
+
turns: [{ toolCalls: [{ name: 'delete_everything', args: {} }] }, { text: 'done' }],
|
|
70
|
+
}),
|
|
71
|
+
model: 'mock-model',
|
|
72
|
+
prompt: 'clean up',
|
|
73
|
+
tools,
|
|
74
|
+
verificationGate: {
|
|
75
|
+
enabled: true,
|
|
76
|
+
rules: [{ type: 'deny_by_name', toolNames: ['delete_everything'] }],
|
|
77
|
+
allowReadOnlyTools: false,
|
|
78
|
+
denyDangerousPatterns: false,
|
|
79
|
+
logDecisions: false,
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
expect(ran).toBe(false)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { MockLLMProvider, registerMock } from '../../provider/index.js'
|
|
4
|
+
import type { RunEvent } from '../../types/run/index.js'
|
|
5
|
+
import { runAgent } from '../runAgent.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `completed` is not `succeeded`.
|
|
9
|
+
*
|
|
10
|
+
* `run_failed` is emitted from exactly one place — the throw path in
|
|
11
|
+
* `result.ts` — so every other way a run can end badly arrives as
|
|
12
|
+
* `run_completed`: the token budget, the timeout, the iteration cap, a
|
|
13
|
+
* cancellation, and a blocking output guardrail. A consumer reading that event
|
|
14
|
+
* as success reported one for a run whose answer was refused, and the CLI did:
|
|
15
|
+
* it mapped `run_completed` to a bare `done` and exited 0.
|
|
16
|
+
*
|
|
17
|
+
* Measured before the fix: a `max_iterations` stop reports
|
|
18
|
+
* `status: 'completed'`, and the event carried nothing to distinguish it.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
registerMock()
|
|
22
|
+
|
|
23
|
+
async function eventsOf(options: Parameters<typeof runAgent>[0]): Promise<RunEvent[]> {
|
|
24
|
+
const events: RunEvent[] = []
|
|
25
|
+
await runAgent({ ...options, listener: (e) => void events.push(e) })
|
|
26
|
+
return events
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function completion(events: RunEvent[]): Extract<RunEvent, { type: 'run_completed' }> | undefined {
|
|
30
|
+
return events.find((e) => e.type === 'run_completed') as never
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('run_completed says why the run stopped', () => {
|
|
34
|
+
it('reports end_turn when the model finished its answer', async () => {
|
|
35
|
+
const events = await eventsOf({
|
|
36
|
+
provider: new MockLLMProvider({ turns: [{ text: 'done' }] }),
|
|
37
|
+
model: 'mock-model',
|
|
38
|
+
prompt: 'x',
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
expect(completion(events)?.stopReason).toBe('end_turn')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('reports max_iterations when the loop was cut short', async () => {
|
|
45
|
+
const events = await eventsOf({
|
|
46
|
+
provider: new MockLLMProvider({ turns: [{ toolCalls: [{ name: 'absent', args: {} }] }] }),
|
|
47
|
+
model: 'mock-model',
|
|
48
|
+
prompt: 'x',
|
|
49
|
+
maxIterations: 1,
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
const done = completion(events)
|
|
53
|
+
// The event that a consumer treats as "the run ended" — and the field
|
|
54
|
+
// that stops it being read as "the run succeeded".
|
|
55
|
+
expect(done).toBeDefined()
|
|
56
|
+
expect(done?.stopReason).toBe('max_iterations')
|
|
57
|
+
expect(events.some((e) => e.type === 'run_failed')).toBe(false)
|
|
58
|
+
})
|
|
59
|
+
})
|
package/src/agents/index.ts
CHANGED
|
@@ -8,4 +8,12 @@ export type { DefineAgentOptions } from './defineAgent.js'
|
|
|
8
8
|
export { InvocationLock, ConcurrentInvocationError } from './lock.js'
|
|
9
9
|
export type { Disposable } from './lock.js'
|
|
10
10
|
export { runAgent } from './runAgent.js'
|
|
11
|
+
// The budgets the front door applies when a caller names none. Exported so a
|
|
12
|
+
// deriver that builds a config by hand lands on the SAME numbers rather than
|
|
13
|
+
// inventing its own or, as `@namzu/project` did, supplying none at all.
|
|
14
|
+
export {
|
|
15
|
+
DEFAULT_MAX_ITERATIONS,
|
|
16
|
+
DEFAULT_TIMEOUT_MS,
|
|
17
|
+
DEFAULT_TOKEN_BUDGET,
|
|
18
|
+
} from './runAgent.js'
|
|
11
19
|
export type { AgentIdentity, RunAgentOptions, RunAgentResult } from './runAgent.js'
|
package/src/agents/runAgent.ts
CHANGED
|
@@ -4,7 +4,9 @@ import type { ProjectId, SessionId, TenantId, ThreadId } from '../types/ids/inde
|
|
|
4
4
|
import type { Message } from '../types/message/index.js'
|
|
5
5
|
import type { LLMProvider } from '../types/provider/index.js'
|
|
6
6
|
import type { Run, RunEventListener } from '../types/run/index.js'
|
|
7
|
+
import type { Skill } from '../types/skills/index.js'
|
|
7
8
|
import type { ToolRegistryContract } from '../types/tool/index.js'
|
|
9
|
+
import type { VerificationGateConfig } from '../types/verification/index.js'
|
|
8
10
|
import {
|
|
9
11
|
generateProjectId,
|
|
10
12
|
generateSessionId,
|
|
@@ -51,6 +53,28 @@ export interface RunAgentOptions extends AgentIdentity {
|
|
|
51
53
|
|
|
52
54
|
tools?: ToolRegistryContract
|
|
53
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Skills to put in front of the model.
|
|
58
|
+
*
|
|
59
|
+
* The kernel has taken these since it had a prompt builder; this door did
|
|
60
|
+
* not forward them, so a caller who assembled skills — `@namzu/project`
|
|
61
|
+
* reads a whole `skills/` directory — handed them over and got a run that
|
|
62
|
+
* had never heard of them. Silent, because the `drainQuery` call below was
|
|
63
|
+
* cast, and a cast seam reports nothing when a field goes missing.
|
|
64
|
+
*/
|
|
65
|
+
skills?: Skill[]
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Operator policy for tool calls: which ones need review before they run.
|
|
69
|
+
*
|
|
70
|
+
* Absent means every tool runs unreviewed, which is the right default for a
|
|
71
|
+
* library front door and the wrong one for a host that hands this an agent
|
|
72
|
+
* directory it did not write. The kernel builds a `VerificationGate` from
|
|
73
|
+
* this and consults it on every call; without it there is nothing to
|
|
74
|
+
* consult, so a front-door run is strictly less mediated than a kernel one.
|
|
75
|
+
*/
|
|
76
|
+
verificationGate?: VerificationGateConfig
|
|
77
|
+
|
|
54
78
|
/** Defaults to the current working directory. */
|
|
55
79
|
workingDirectory?: string
|
|
56
80
|
|
|
@@ -90,9 +114,9 @@ export interface RunAgentResult {
|
|
|
90
114
|
* dollars, and an iteration cap that stops a tool-calling loop well before a
|
|
91
115
|
* context window does. Every one is overridable and named on the option.
|
|
92
116
|
*/
|
|
93
|
-
const DEFAULT_MAX_ITERATIONS = 16
|
|
94
|
-
const DEFAULT_TOKEN_BUDGET = 200_000
|
|
95
|
-
const DEFAULT_TIMEOUT_MS = 300_000
|
|
117
|
+
export const DEFAULT_MAX_ITERATIONS = 16
|
|
118
|
+
export const DEFAULT_TOKEN_BUDGET = 200_000
|
|
119
|
+
export const DEFAULT_TIMEOUT_MS = 300_000
|
|
96
120
|
|
|
97
121
|
/**
|
|
98
122
|
* Run an agent, without assembling a kernel by hand.
|
|
@@ -170,8 +194,10 @@ export async function runAgent(options: RunAgentOptions): Promise<RunAgentResult
|
|
|
170
194
|
agentName: options.name ?? 'Agent',
|
|
171
195
|
...(options.instructions ? { systemPrompt: options.instructions } : {}),
|
|
172
196
|
...(options.signal ? { signal: options.signal } : {}),
|
|
197
|
+
...(options.skills ? { skills: options.skills } : {}),
|
|
198
|
+
...(options.verificationGate ? { verificationGate: options.verificationGate } : {}),
|
|
173
199
|
...identity,
|
|
174
|
-
}
|
|
200
|
+
},
|
|
175
201
|
options.listener,
|
|
176
202
|
)
|
|
177
203
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { DANGEROUS_PATTERNS } from '../index.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `DANGEROUS_PATTERNS` is what `deny_dangerous_patterns` consults, and
|
|
7
|
+
* `namzu run`'s own docstring promises that in a non-interactive run "the
|
|
8
|
+
* safety gate still hard-denies catastrophic commands".
|
|
9
|
+
*
|
|
10
|
+
* The fork-bomb entry could not deny one. It was written `/:(){ :\|:& };:/`,
|
|
11
|
+
* and in a regular expression `()` is an empty capture group rather than two
|
|
12
|
+
* literal parentheses — so the pattern described `:{ :|:& };:`, a string that
|
|
13
|
+
* is not valid shell and that nobody types. The list looked complete in review
|
|
14
|
+
* and had a hole in it that only running the regex reveals.
|
|
15
|
+
*
|
|
16
|
+
* No test named a fork bomb before this one, which is how it survived.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
function denies(command: string): boolean {
|
|
20
|
+
return DANGEROUS_PATTERNS.some((p) => p.test(command))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('the dangerous-command list denies fork bombs', () => {
|
|
24
|
+
// Spelling varies with whitespace and with the function's name; the bomb
|
|
25
|
+
// does not care, so neither may the pattern.
|
|
26
|
+
it.each([
|
|
27
|
+
':(){ :|:& };:',
|
|
28
|
+
':(){:|:&};:',
|
|
29
|
+
':() { :|:& }; :',
|
|
30
|
+
':(){ : | : & }; :',
|
|
31
|
+
'bomb(){ bomb|bomb& }; bomb',
|
|
32
|
+
'f(){ f|f& };f',
|
|
33
|
+
])('denies %j', (command) => {
|
|
34
|
+
expect(denies(command)).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('it does not deny ordinary shell', () => {
|
|
39
|
+
// A function containing a pipe and a background job is not a fork bomb.
|
|
40
|
+
// The signature is SELF-reference — the same name on both sides — and a
|
|
41
|
+
// pattern that fired on the general shape would make the gate useless by
|
|
42
|
+
// crying wolf.
|
|
43
|
+
it.each([
|
|
44
|
+
'build(){ make | tee log & }',
|
|
45
|
+
'watch(){ tail -f log | grep ERROR & }; watch',
|
|
46
|
+
'f(){ g|h& };f',
|
|
47
|
+
'run(){ a|b& }; run',
|
|
48
|
+
'git log | head -20',
|
|
49
|
+
'npm test',
|
|
50
|
+
])('allows %j', (command) => {
|
|
51
|
+
expect(denies(command)).toBe(false)
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
describe('the rest of the list still fires', () => {
|
|
56
|
+
it.each(['rm -rf /', 'mkfs.ext4 /dev/sda', 'dd if=/dev/zero of=/dev/sda', 'sudo rm x'])(
|
|
57
|
+
'denies %j',
|
|
58
|
+
(command) => {
|
|
59
|
+
expect(denies(command)).toBe(true)
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
})
|
|
@@ -17,7 +17,34 @@ export const DANGEROUS_PATTERNS = [
|
|
|
17
17
|
/rm\s+-rf\s+\//,
|
|
18
18
|
/mkfs/,
|
|
19
19
|
/dd\s+if=/,
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Fork bomb.
|
|
22
|
+
*
|
|
23
|
+
* The previous entry was `/:(){ :\|:& };:/`, which could not match one. In
|
|
24
|
+
* a regular expression `()` is an empty capture group, not two literal
|
|
25
|
+
* parentheses, so that pattern described the string `:{ :|:& };:` — which
|
|
26
|
+
* is not valid shell and which nobody would ever type. Probed: it returned
|
|
27
|
+
* false for `:(){ :|:& };:` and every spelling of it, while `run.ts`'s own
|
|
28
|
+
* docstring promised "the safety gate still hard-denies catastrophic
|
|
29
|
+
* commands".
|
|
30
|
+
*
|
|
31
|
+
* Matched on SELF-REFERENCE rather than on one literal spelling: a fork
|
|
32
|
+
* bomb is a function whose own name appears on both sides of a pipe, is
|
|
33
|
+
* backgrounded, and is then invoked. That is what separates it from a
|
|
34
|
+
* function that merely contains a pipe — `watch(){ tail -f log | grep E & }`
|
|
35
|
+
* does not match, and `bomb(){ bomb|bomb& }; bomb` does.
|
|
36
|
+
*
|
|
37
|
+
* EVERY run is bounded, not just the name. The first version bounded the
|
|
38
|
+
* name and left the gaps as `\s*`, and static analysis caught what a hand
|
|
39
|
+
* probe did not: a chain of unbounded runs backtracks polynomially, and
|
|
40
|
+
* this list is matched against SERIALIZED TOOL INPUT — model output, which
|
|
41
|
+
* a prompt injection can shape. A denial of service in the check that
|
|
42
|
+
* exists to prevent one is the wrong way round.
|
|
43
|
+
*
|
|
44
|
+
* `[ \t]` rather than `\s`, because a shell function definition of this
|
|
45
|
+
* shape lives on one line, and the bound is generous for real spacing.
|
|
46
|
+
*/
|
|
47
|
+
/([\w.]{1,32}|:)[ \t]{0,8}\([ \t]{0,8}\)[ \t]{0,8}\{[ \t]{0,8}\1[ \t]{0,8}\|[ \t]{0,8}\1[ \t]{0,8}&[ \t]{0,8};?[ \t]{0,8}\}[ \t]{0,8};?[ \t]{0,8}\1/,
|
|
21
48
|
// Privilege escalation + world-writable chmod on /.
|
|
22
49
|
/\bsudo\b/,
|
|
23
50
|
/\bsu\s+-/,
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { tmpdir } from 'node:os'
|
|
3
|
+
import { join } from 'node:path'
|
|
4
|
+
import { describe, expect, it } from 'vitest'
|
|
5
|
+
|
|
6
|
+
import { deriveRunOptions } from '../derive.js'
|
|
7
|
+
import { loadDirectory } from '../load.js'
|
|
8
|
+
|
|
9
|
+
const provider = { id: 'mock', name: 'Mock' } as never
|
|
10
|
+
|
|
11
|
+
function project(files: Record<string, string>): string {
|
|
12
|
+
const root = mkdtempSync(join(tmpdir(), 'namzu-derive-'))
|
|
13
|
+
for (const [relative, body] of Object.entries(files)) {
|
|
14
|
+
const full = join(root, relative)
|
|
15
|
+
mkdirSync(join(full, '..'), { recursive: true })
|
|
16
|
+
writeFileSync(full, body)
|
|
17
|
+
}
|
|
18
|
+
return root
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const TOOL = (name: string) => `
|
|
22
|
+
export default {
|
|
23
|
+
name: ${JSON.stringify(name)},
|
|
24
|
+
description: 'a tool',
|
|
25
|
+
inputSchema: { parse: (v) => v, safeParse: (v) => ({ success: true, data: v }) },
|
|
26
|
+
execute: async () => ({ success: true, output: 'ok' }),
|
|
27
|
+
}
|
|
28
|
+
`
|
|
29
|
+
|
|
30
|
+
describe('turning a manifest into run options', () => {
|
|
31
|
+
it('carries instructions, config and tools across', async () => {
|
|
32
|
+
const root = project({
|
|
33
|
+
'instructions.md': 'You are terse.',
|
|
34
|
+
'agent.js': 'export default { model: "m", maxIterations: 3 }',
|
|
35
|
+
'tools/a.js': TOOL('a'),
|
|
36
|
+
})
|
|
37
|
+
const { manifest } = await loadDirectory(root)
|
|
38
|
+
|
|
39
|
+
const options = deriveRunOptions(manifest, { provider, prompt: 'hi' })
|
|
40
|
+
|
|
41
|
+
expect(options.model).toBe('m')
|
|
42
|
+
expect(options.instructions).toBe('You are terse.')
|
|
43
|
+
expect(options.maxIterations).toBe(3)
|
|
44
|
+
expect(options.tools?.has('a')).toBe(true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('points the working directory at the project, not the host', async () => {
|
|
48
|
+
// Left unset this defaults to the host's cwd, which aims the file
|
|
49
|
+
// tools' containment at the host's own source tree.
|
|
50
|
+
const root = project({
|
|
51
|
+
'instructions.md': 'hi',
|
|
52
|
+
'agent.js': 'export default { model: "m" }',
|
|
53
|
+
})
|
|
54
|
+
const { manifest } = await loadDirectory(root)
|
|
55
|
+
|
|
56
|
+
expect(deriveRunOptions(manifest, { provider, prompt: 'hi' }).workingDirectory).toBe(
|
|
57
|
+
manifest.root,
|
|
58
|
+
)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('lets an explicit model win over agent.ts', async () => {
|
|
62
|
+
const root = project({
|
|
63
|
+
'instructions.md': 'hi',
|
|
64
|
+
'agent.js': 'export default { model: "from-file" }',
|
|
65
|
+
})
|
|
66
|
+
const { manifest } = await loadDirectory(root)
|
|
67
|
+
|
|
68
|
+
expect(deriveRunOptions(manifest, { provider, prompt: 'hi', model: 'explicit' }).model).toBe(
|
|
69
|
+
'explicit',
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('refuses when nothing names a model', async () => {
|
|
74
|
+
const root = project({ 'instructions.md': 'hi' })
|
|
75
|
+
const { manifest } = await loadDirectory(root)
|
|
76
|
+
|
|
77
|
+
expect(() => deriveRunOptions(manifest, { provider, prompt: 'hi' })).toThrow(/No model/)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('forwards a name only when agent.ts declared one', async () => {
|
|
81
|
+
// A name guessed from a directory basename becomes the agent id in
|
|
82
|
+
// traces, where two sibling projects both called `agent` merge into one
|
|
83
|
+
// attribution bucket.
|
|
84
|
+
const declared = project({
|
|
85
|
+
'instructions.md': 'hi',
|
|
86
|
+
'agent.js': 'export default { model: "m", name: "researcher" }',
|
|
87
|
+
})
|
|
88
|
+
const guessed = project({
|
|
89
|
+
'instructions.md': 'hi',
|
|
90
|
+
'agent.js': 'export default { model: "m" }',
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const withName = deriveRunOptions((await loadDirectory(declared)).manifest, {
|
|
94
|
+
provider,
|
|
95
|
+
prompt: 'x',
|
|
96
|
+
})
|
|
97
|
+
const without = deriveRunOptions((await loadDirectory(guessed)).manifest, {
|
|
98
|
+
provider,
|
|
99
|
+
prompt: 'x',
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
expect(withName.name).toBe('researcher')
|
|
103
|
+
expect(without.name).toBeUndefined()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
it('refuses a manifest whose modules were never loaded', async () => {
|
|
107
|
+
// `manifest.tools` is empty for a reason that has nothing to do with
|
|
108
|
+
// the project. Running it would produce an agent with no capabilities
|
|
109
|
+
// and no indication why.
|
|
110
|
+
const root = project({
|
|
111
|
+
'instructions.md': 'hi',
|
|
112
|
+
'agent.js': 'export default { model: "m" }',
|
|
113
|
+
'tools/a.js': TOOL('a'),
|
|
114
|
+
})
|
|
115
|
+
const { manifest } = await loadDirectory(root, { modules: 'skip' })
|
|
116
|
+
|
|
117
|
+
expect(() => deriveRunOptions(manifest, { provider, prompt: 'hi' })).toThrow(/modules: "skip"/)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('lets overrides win over everything', async () => {
|
|
121
|
+
const root = project({
|
|
122
|
+
'instructions.md': 'hi',
|
|
123
|
+
'agent.js': 'export default { model: "m", maxIterations: 3 }',
|
|
124
|
+
})
|
|
125
|
+
const { manifest } = await loadDirectory(root)
|
|
126
|
+
|
|
127
|
+
const options = deriveRunOptions(manifest, {
|
|
128
|
+
provider,
|
|
129
|
+
prompt: 'hi',
|
|
130
|
+
overrides: { maxIterations: 99 },
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
expect(options.maxIterations).toBe(99)
|
|
134
|
+
})
|
|
135
|
+
})
|