@alisio/core 0.1.0-alpha.21 → 0.1.0-alpha.22
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/analysis/capabilities.d.ts +48 -0
- package/dist/analysis/capabilities.js +90 -0
- package/dist/analysis/data/csv.d.ts +46 -0
- package/dist/analysis/data/csv.js +240 -0
- package/dist/analysis/data/datasets.d.ts +132 -0
- package/dist/analysis/data/datasets.js +441 -0
- package/dist/analysis/data/describe.d.ts +27 -0
- package/dist/analysis/data/describe.js +103 -0
- package/dist/analysis/data/engine-client.d.ts +58 -0
- package/dist/analysis/data/engine-client.js +304 -0
- package/dist/analysis/data/engine-entry.d.ts +1 -0
- package/dist/analysis/data/engine-entry.js +59 -0
- package/dist/analysis/data/engine-source.d.ts +4 -0
- package/dist/analysis/data/engine-source.js +6 -0
- package/dist/analysis/data/engine-types.d.ts +86 -0
- package/dist/analysis/data/engine-types.js +7 -0
- package/dist/analysis/data/infer.d.ts +42 -0
- package/dist/analysis/data/infer.js +118 -0
- package/dist/analysis/data/ingest-worker.d.ts +17 -0
- package/dist/analysis/data/ingest-worker.js +365 -0
- package/dist/analysis/data/json.d.ts +19 -0
- package/dist/analysis/data/json.js +44 -0
- package/dist/analysis/data/query-worker.d.ts +12 -0
- package/dist/analysis/data/query-worker.js +75 -0
- package/dist/analysis/data/rows.d.ts +39 -0
- package/dist/analysis/data/rows.js +120 -0
- package/dist/analysis/data/sql-guard.d.ts +20 -0
- package/dist/analysis/data/sql-guard.js +129 -0
- package/dist/analysis/data/stats.d.ts +18 -0
- package/dist/analysis/data/stats.js +77 -0
- package/dist/analysis/install-hints.d.ts +33 -0
- package/dist/analysis/install-hints.js +144 -0
- package/dist/analysis/janitor.d.ts +60 -0
- package/dist/analysis/janitor.js +264 -0
- package/dist/analysis/jobs.d.ts +94 -0
- package/dist/analysis/jobs.js +165 -0
- package/dist/analysis/oci.d.ts +129 -0
- package/dist/analysis/oci.js +330 -0
- package/dist/analysis/python/sources.d.ts +2 -0
- package/dist/analysis/python/sources.js +10 -0
- package/dist/analysis/requirements.d.ts +32 -0
- package/dist/analysis/requirements.js +73 -0
- package/dist/analysis/rerun.d.ts +40 -0
- package/dist/analysis/rerun.js +136 -0
- package/dist/analysis/runtime-manager.d.ts +146 -0
- package/dist/analysis/runtime-manager.js +472 -0
- package/dist/analysis/status.d.ts +21 -0
- package/dist/analysis/status.js +52 -0
- package/dist/application.d.ts +41 -0
- package/dist/application.js +195 -0
- package/dist/artifacts/kinds.d.ts +35 -0
- package/dist/artifacts/kinds.js +177 -0
- package/dist/artifacts/publisher.d.ts +7 -0
- package/dist/artifacts/publisher.js +29 -0
- package/dist/artifacts/store.d.ts +119 -0
- package/dist/artifacts/store.js +581 -0
- package/dist/commands/builtins.js +13 -0
- package/dist/config.d.ts +102 -0
- package/dist/config.js +167 -6
- package/dist/core/contracts.d.ts +69 -1
- package/dist/core/runner.d.ts +34 -4
- package/dist/core/runner.js +388 -130
- package/dist/index.d.ts +23 -4
- package/dist/index.js +22 -3
- package/dist/mcp/rich.js +4 -0
- package/dist/plugins/host.js +14 -6
- package/dist/runtime/blobs.d.ts +22 -0
- package/dist/runtime/blobs.js +84 -1
- package/dist/runtime/ids.d.ts +8 -0
- package/dist/runtime/ids.js +32 -0
- package/dist/runtime/paths.d.ts +5 -0
- package/dist/runtime/paths.js +6 -0
- package/dist/runtime/process.d.ts +12 -0
- package/dist/runtime/process.js +64 -4
- package/dist/runtime/sqlite.d.ts +2 -0
- package/dist/runtime/sqlite.js +18 -0
- package/dist/runtime/store.d.ts +5 -0
- package/dist/runtime/store.js +75 -0
- package/dist/runtime/zip.d.ts +24 -0
- package/dist/runtime/zip.js +126 -0
- package/dist/sessions/children.js +4 -0
- package/dist/tools/analysis.d.ts +37 -0
- package/dist/tools/analysis.js +572 -0
- package/dist/tools/artifacts.d.ts +14 -0
- package/dist/tools/artifacts.js +143 -0
- package/dist/tools/data.d.ts +7 -0
- package/dist/tools/data.js +160 -0
- package/dist/tools/execute.js +6 -2
- package/package.json +2 -2
package/dist/core/runner.js
CHANGED
|
@@ -17,7 +17,19 @@ const MAX_INJECT_CHARS = 24_000;
|
|
|
17
17
|
* fails with an actionable error instead of silently losing the whole history.
|
|
18
18
|
*/
|
|
19
19
|
const MIN_MESSAGE_BUDGET_FLOOR = 4_000;
|
|
20
|
-
const allowed = (policy, effect) => effect === "read" ||
|
|
20
|
+
const allowed = (policy, effect) => effect === "read" ||
|
|
21
|
+
effect === "internal" ||
|
|
22
|
+
((effect === "write" || effect === "process" || effect === "external") && !!policy[effect]);
|
|
23
|
+
/** A tool's capability is pre-allowed by the policy alone (`--allow-analysis`). */
|
|
24
|
+
const capabilityAllowed = (policy, tool) => tool.capability === "analysis.run" && !!policy.analysis;
|
|
25
|
+
/** First 40 lines of a script input, for capability approvals. */
|
|
26
|
+
const scriptPreview = (input) => typeof input.code === "string" ? input.code.split(/\r?\n/).slice(0, 40).join("\n") : undefined;
|
|
27
|
+
/** A short id for a tool call the user started from a UI (alphanumeric, 9 characters). */
|
|
28
|
+
const uiCallId = () => {
|
|
29
|
+
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
30
|
+
const bytes = crypto.getRandomValues(new Uint8Array(9));
|
|
31
|
+
return Array.from(bytes, (b) => alphabet[b % alphabet.length]).join("");
|
|
32
|
+
};
|
|
21
33
|
export class AgentRunner {
|
|
22
34
|
options;
|
|
23
35
|
/** Sessions with an active run or compaction (one at a time per session). */
|
|
@@ -80,8 +92,11 @@ export class AgentRunner {
|
|
|
80
92
|
}
|
|
81
93
|
};
|
|
82
94
|
}
|
|
83
|
-
/**
|
|
84
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Tools offered to the model under the current policy (and optional run narrowing). With a
|
|
97
|
+
* session, a capability tool is also offered when that session's root holds a persisted grant.
|
|
98
|
+
*/
|
|
99
|
+
availableTools(run = {}, sessionId) {
|
|
85
100
|
const o = this.options;
|
|
86
101
|
const policy = run.policy ?? o.policy;
|
|
87
102
|
const approvals = !!o.approve && run.approvals !== false;
|
|
@@ -91,6 +106,12 @@ export class AgentRunner {
|
|
|
91
106
|
const effect = t.effect ?? "external";
|
|
92
107
|
if (allowed(policy, effect))
|
|
93
108
|
return true;
|
|
109
|
+
if (t.capability) {
|
|
110
|
+
if (capabilityAllowed(policy, t))
|
|
111
|
+
return true;
|
|
112
|
+
if (sessionId && o.capabilities?.granted(t.capability, sessionId))
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
94
115
|
return approvals && (effect === "write" || effect === "process" || effect === "external");
|
|
95
116
|
});
|
|
96
117
|
}
|
|
@@ -310,6 +331,343 @@ export class AgentRunner {
|
|
|
310
331
|
throw error;
|
|
311
332
|
}
|
|
312
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* Gates and executes one tool call: external-directory paths, the capability/effect gate with
|
|
336
|
+
* its approval, the call journal, artifact publishing and the result bound. Shared by model
|
|
337
|
+
* runs and `runToolCall`, so a call started from a UI passes exactly the same gates.
|
|
338
|
+
*/
|
|
339
|
+
async executeCall(scope, p) {
|
|
340
|
+
const o = this.options;
|
|
341
|
+
const { sessionId, runId, emit, workspace, policy, approvals, options } = scope;
|
|
342
|
+
const combined = scope.signal;
|
|
343
|
+
const pathAccess = o.pathAccess;
|
|
344
|
+
const { call } = p;
|
|
345
|
+
let result;
|
|
346
|
+
const started = Date.now();
|
|
347
|
+
// `effect` rides along so the TUI can group consecutive calls by capability kind
|
|
348
|
+
// (read batches, write batches, commands…) without a name heuristic. Additive field.
|
|
349
|
+
emit("tool_started", {
|
|
350
|
+
name: call.name,
|
|
351
|
+
id: call.id,
|
|
352
|
+
arguments: call.arguments,
|
|
353
|
+
effect: p.tool?.effect ?? "external",
|
|
354
|
+
});
|
|
355
|
+
try {
|
|
356
|
+
combined.throwIfAborted();
|
|
357
|
+
if (p.error)
|
|
358
|
+
throw new Error(p.error);
|
|
359
|
+
if (!p.tool || !p.input)
|
|
360
|
+
throw new Error("Invalid tool");
|
|
361
|
+
const effect = p.tool.effect ?? "external";
|
|
362
|
+
// External-directory prerequisite: declared paths are resolved (and, outside every
|
|
363
|
+
// allowed root, approved for the containing directory) BEFORE the effect gate, so a
|
|
364
|
+
// write still needs its own write policy and a read never hard-throws first. The
|
|
365
|
+
// resolved map keeps "allow once" scoped to this one call, with no shared mutable
|
|
366
|
+
// state that parallel read batches could race on.
|
|
367
|
+
const resolved = new Map();
|
|
368
|
+
if (pathAccess)
|
|
369
|
+
for (const declared of p.tool.paths?.(p.input) ?? [])
|
|
370
|
+
if (!resolved.has(declared)) {
|
|
371
|
+
const target = await pathAccess.resolve(declared, {
|
|
372
|
+
workspace,
|
|
373
|
+
session: sessionId,
|
|
374
|
+
...(options.label ? { label: options.label } : {}),
|
|
375
|
+
signal: combined,
|
|
376
|
+
});
|
|
377
|
+
// Key both the declared input and its resolved form: a write resolves the
|
|
378
|
+
// input once, then re-checks the already-absolute path, and neither lookup may
|
|
379
|
+
// ask a second time for an "allow once" decision.
|
|
380
|
+
resolved.set(declared, target);
|
|
381
|
+
resolved.set(target, target);
|
|
382
|
+
}
|
|
383
|
+
scope.guard?.(effect);
|
|
384
|
+
if (options.toolFilter && !options.toolFilter(p.tool))
|
|
385
|
+
throw new Error(`Tool ${call.name} is not available in this session`);
|
|
386
|
+
const capability = p.tool.capability;
|
|
387
|
+
const gate = o.capabilities;
|
|
388
|
+
if (capability && (allowed(policy, effect) || capabilityAllowed(policy, p.tool))) {
|
|
389
|
+
// A broad process grant or --allow-analysis: allowed, audited as a flag decision.
|
|
390
|
+
gate?.record({
|
|
391
|
+
capability,
|
|
392
|
+
sessionId,
|
|
393
|
+
scope: "once",
|
|
394
|
+
decision: "allow",
|
|
395
|
+
source: "flag",
|
|
396
|
+
callId: call.id,
|
|
397
|
+
runId,
|
|
398
|
+
...(options.correlationId !== undefined ? { correlationId: options.correlationId } : {}),
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
else if (capability && gate?.granted(capability, sessionId)) {
|
|
402
|
+
// A persisted "allow for this session" grant of the root session.
|
|
403
|
+
}
|
|
404
|
+
else if (!allowed(policy, effect)) {
|
|
405
|
+
if (!o.approve ||
|
|
406
|
+
!approvals ||
|
|
407
|
+
(effect !== "write" && effect !== "process" && effect !== "external"))
|
|
408
|
+
throw new Error(`Capability denied: ${capability ?? effect}`);
|
|
409
|
+
const preview = capability
|
|
410
|
+
? (scriptPreview(p.input) ?? (await gate?.preview?.(p.input, sessionId)))
|
|
411
|
+
: undefined;
|
|
412
|
+
emit("approval_requested", {
|
|
413
|
+
id: call.id,
|
|
414
|
+
name: call.name,
|
|
415
|
+
effect,
|
|
416
|
+
...(options.label ? { label: options.label } : {}),
|
|
417
|
+
...(capability ? { capability } : {}),
|
|
418
|
+
});
|
|
419
|
+
const decision = await o.approve({
|
|
420
|
+
call,
|
|
421
|
+
effect,
|
|
422
|
+
input: p.input,
|
|
423
|
+
signal: combined,
|
|
424
|
+
session: sessionId,
|
|
425
|
+
...(options.label ? { label: options.label } : {}),
|
|
426
|
+
...(capability ? { capability } : {}),
|
|
427
|
+
...(preview !== undefined ? { preview } : {}),
|
|
428
|
+
...(capability && gate?.runtime ? { runtime: gate.runtime } : {}),
|
|
429
|
+
});
|
|
430
|
+
combined.throwIfAborted();
|
|
431
|
+
const persisted = !!capability && !!gate && decision === "session";
|
|
432
|
+
if (capability && gate)
|
|
433
|
+
gate.record({
|
|
434
|
+
capability,
|
|
435
|
+
sessionId,
|
|
436
|
+
scope: decision === "session" ? "session" : "once",
|
|
437
|
+
decision: decision === "deny" ? "deny" : "allow",
|
|
438
|
+
source: gate.source ?? "tui",
|
|
439
|
+
callId: call.id,
|
|
440
|
+
runId,
|
|
441
|
+
...(options.correlationId !== undefined
|
|
442
|
+
? { correlationId: options.correlationId }
|
|
443
|
+
: {}),
|
|
444
|
+
});
|
|
445
|
+
emit("approval_resolved", {
|
|
446
|
+
id: call.id,
|
|
447
|
+
name: call.name,
|
|
448
|
+
effect,
|
|
449
|
+
decision,
|
|
450
|
+
...(capability ? { capability } : {}),
|
|
451
|
+
...(persisted ? { persisted: true } : {}),
|
|
452
|
+
});
|
|
453
|
+
if (decision === "deny")
|
|
454
|
+
throw new Error(`Capability ${capability ?? effect} denied by the user for this call`);
|
|
455
|
+
// A capability grant never widens the effect: only effect approvals do.
|
|
456
|
+
if (decision === "session" && !capability)
|
|
457
|
+
policy[effect] = true;
|
|
458
|
+
}
|
|
459
|
+
o.store.beginCall(sessionId, call, { runId, effect });
|
|
460
|
+
const publisher = o.artifacts?.({ sessionId, runId, callId: call.id }, (published) => emit("artifact_published", {
|
|
461
|
+
artifact: published.artifact,
|
|
462
|
+
path: published.path,
|
|
463
|
+
callId: call.id,
|
|
464
|
+
...(published.executionId ? { executionId: published.executionId } : {}),
|
|
465
|
+
}));
|
|
466
|
+
/**
|
|
467
|
+
* `analysis.install`: always asks, `once` only, and no flag or earlier grant covers it. Where
|
|
468
|
+
* nobody can be asked (headless, no approval handler) the answer is `deny`.
|
|
469
|
+
*/
|
|
470
|
+
const approveInstall = async (install) => {
|
|
471
|
+
if (!o.approve || !approvals)
|
|
472
|
+
return "deny";
|
|
473
|
+
const installCall = { ...call, id: `${call.id}:install` };
|
|
474
|
+
emit("approval_requested", {
|
|
475
|
+
id: installCall.id,
|
|
476
|
+
name: call.name,
|
|
477
|
+
effect: "process",
|
|
478
|
+
...(options.label ? { label: options.label } : {}),
|
|
479
|
+
capability: "analysis.install",
|
|
480
|
+
install,
|
|
481
|
+
});
|
|
482
|
+
let decision = "deny";
|
|
483
|
+
try {
|
|
484
|
+
decision = await o.approve({
|
|
485
|
+
call: installCall,
|
|
486
|
+
effect: "process",
|
|
487
|
+
input: { extras: install.extras },
|
|
488
|
+
signal: combined,
|
|
489
|
+
session: sessionId,
|
|
490
|
+
...(options.label ? { label: options.label } : {}),
|
|
491
|
+
capability: "analysis.install",
|
|
492
|
+
install,
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
finally {
|
|
496
|
+
combined.throwIfAborted();
|
|
497
|
+
}
|
|
498
|
+
// A `session` answer is treated as `once`: an installation permission is never stored.
|
|
499
|
+
const allowedNow = decision !== "deny";
|
|
500
|
+
gate?.record({
|
|
501
|
+
capability: "analysis.install",
|
|
502
|
+
sessionId,
|
|
503
|
+
scope: "once",
|
|
504
|
+
decision: allowedNow ? "allow" : "deny",
|
|
505
|
+
source: gate.source ?? "tui",
|
|
506
|
+
callId: call.id,
|
|
507
|
+
runId,
|
|
508
|
+
...(options.correlationId !== undefined ? { correlationId: options.correlationId } : {}),
|
|
509
|
+
});
|
|
510
|
+
emit("approval_resolved", {
|
|
511
|
+
id: installCall.id,
|
|
512
|
+
name: call.name,
|
|
513
|
+
effect: "process",
|
|
514
|
+
decision: allowedNow ? "once" : "deny",
|
|
515
|
+
capability: "analysis.install",
|
|
516
|
+
});
|
|
517
|
+
return allowedNow ? "once" : "deny";
|
|
518
|
+
};
|
|
519
|
+
result = await p.tool.execute(p.input, {
|
|
520
|
+
signal: combined,
|
|
521
|
+
workspace,
|
|
522
|
+
session: sessionId,
|
|
523
|
+
runId,
|
|
524
|
+
callId: call.id,
|
|
525
|
+
...(publisher ? { artifacts: publisher } : {}),
|
|
526
|
+
approveInstall,
|
|
527
|
+
emit: (data) => emit("tool_progress", { id: call.id, data }),
|
|
528
|
+
...(options.label ? { label: options.label } : {}),
|
|
529
|
+
...(pathAccess
|
|
530
|
+
? {
|
|
531
|
+
resolvePath: (path) => {
|
|
532
|
+
const known = resolved.get(path);
|
|
533
|
+
return known !== undefined
|
|
534
|
+
? Promise.resolve(known)
|
|
535
|
+
: pathAccess.resolve(path, {
|
|
536
|
+
workspace,
|
|
537
|
+
session: sessionId,
|
|
538
|
+
...(options.label ? { label: options.label } : {}),
|
|
539
|
+
signal: combined,
|
|
540
|
+
});
|
|
541
|
+
},
|
|
542
|
+
}
|
|
543
|
+
: {}),
|
|
544
|
+
});
|
|
545
|
+
// The bound applies to what the model sees (the text projection): display-only
|
|
546
|
+
// ui/image parts are bounded by their producers and must not push text over it.
|
|
547
|
+
const projected = textProjection(result);
|
|
548
|
+
if (JSON.stringify(projected).length > 48_000)
|
|
549
|
+
result = textResult(`${JSON.stringify(projected).slice(0, 40_000)}\n[tool output truncated]`, result.isError);
|
|
550
|
+
result = scope.amend?.(result, effect) ?? result;
|
|
551
|
+
o.store.endCall(sessionId, call, result);
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
result = textResult(error instanceof Error ? error.message : String(error), true);
|
|
555
|
+
// A cancellation after execution may have left effects; journal remains pending.
|
|
556
|
+
if (!combined.aborted)
|
|
557
|
+
o.store.endCall(sessionId, call, result);
|
|
558
|
+
}
|
|
559
|
+
emit("tool_completed", {
|
|
560
|
+
id: call.id,
|
|
561
|
+
name: call.name,
|
|
562
|
+
isError: result.isError ?? false,
|
|
563
|
+
durationMs: Date.now() - started,
|
|
564
|
+
preview: result.content
|
|
565
|
+
.filter((part) => part.type === "text")
|
|
566
|
+
.map((c) => c.text)
|
|
567
|
+
.join("\n")
|
|
568
|
+
.slice(0, 2_000),
|
|
569
|
+
});
|
|
570
|
+
return result;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Runs ONE tool call without a model (spec §20 `runToolCall`): an action the user started from
|
|
574
|
+
* a UI, such as copying an artifact into the workspace. It is a real run of the session
|
|
575
|
+
* (`run_started` → `tool_*` → `run_completed`, journaled) and the call passes exactly the gates
|
|
576
|
+
* of a model call (`write` approval, capabilities, paths). The transcript stays valid for every
|
|
577
|
+
* provider: a user note (shown as `display`), an assistant message with the call, the tool
|
|
578
|
+
* result and a short assistant summary.
|
|
579
|
+
*/
|
|
580
|
+
async runToolCall(sessionId, name, input, options = {}) {
|
|
581
|
+
const controller = this.claim(sessionId);
|
|
582
|
+
const runId = options.runId ?? crypto.randomUUID();
|
|
583
|
+
const o = this.options, emit = this.emitter(sessionId, { runId, correlationId: options.correlationId });
|
|
584
|
+
const finish = (status, error) => {
|
|
585
|
+
try {
|
|
586
|
+
o.store.endRun?.(runId, {
|
|
587
|
+
status,
|
|
588
|
+
usage: { input: 0, output: 0 },
|
|
589
|
+
...(error ? { error } : {}),
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
catch {
|
|
593
|
+
/* A journal write failure cannot invalidate an executed run. */
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
const timeout = AbortSignal.timeout(options.timeoutMs ?? o.timeoutMs ?? 300_000);
|
|
597
|
+
const combined = AbortSignal.any([
|
|
598
|
+
controller.signal,
|
|
599
|
+
timeout,
|
|
600
|
+
...(options.signal ? [options.signal] : []),
|
|
601
|
+
]);
|
|
602
|
+
const workspace = options.workspace ?? o.workspace;
|
|
603
|
+
let acquired = false;
|
|
604
|
+
try {
|
|
605
|
+
o.store.beginRun?.({
|
|
606
|
+
id: runId,
|
|
607
|
+
session: sessionId,
|
|
608
|
+
status: "running",
|
|
609
|
+
model: o.store.get(sessionId).model,
|
|
610
|
+
...(options.correlationId !== undefined ? { correlationId: options.correlationId } : {}),
|
|
611
|
+
});
|
|
612
|
+
o.store.acquire(sessionId);
|
|
613
|
+
acquired = true;
|
|
614
|
+
o.store.reconcile(sessionId);
|
|
615
|
+
const session = o.store.get(sessionId);
|
|
616
|
+
if (session.workspace !== workspace)
|
|
617
|
+
throw new Error("Session workspace mismatch");
|
|
618
|
+
combined.throwIfAborted();
|
|
619
|
+
const call = { id: uiCallId(), name, arguments: JSON.stringify(input) };
|
|
620
|
+
let prepared;
|
|
621
|
+
try {
|
|
622
|
+
prepared = {
|
|
623
|
+
call,
|
|
624
|
+
tool: o.registry.get(name),
|
|
625
|
+
input: o.registry.parse(name, call.arguments),
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
catch (error) {
|
|
629
|
+
prepared = { call, error: String(error) };
|
|
630
|
+
}
|
|
631
|
+
const note = `The user ran the ${name} tool from the interface.`;
|
|
632
|
+
o.store.append(sessionId, { role: "user", text: note, display: options.display ?? note });
|
|
633
|
+
emit("run_started", { model: session.model });
|
|
634
|
+
o.store.append(sessionId, { role: "assistant", text: "", calls: [call] });
|
|
635
|
+
const result = await this.executeCall({
|
|
636
|
+
sessionId,
|
|
637
|
+
runId,
|
|
638
|
+
emit,
|
|
639
|
+
signal: combined,
|
|
640
|
+
workspace,
|
|
641
|
+
policy: options.policy ?? o.policy,
|
|
642
|
+
approvals: !!o.approve && options.approvals !== false,
|
|
643
|
+
options,
|
|
644
|
+
}, prepared);
|
|
645
|
+
o.store.append(sessionId, { role: "tool", callId: call.id, result });
|
|
646
|
+
const first = textProjection(result)
|
|
647
|
+
.content.map((part) => (part.type === "text" ? part.text : ""))
|
|
648
|
+
.join(" ")
|
|
649
|
+
.replace(/\s*\n\s*/g, " ")
|
|
650
|
+
.trim()
|
|
651
|
+
.slice(0, 300);
|
|
652
|
+
const text = `${name} ${result.isError ? "failed" : "finished"}${first ? `: ${first}` : ""}`;
|
|
653
|
+
o.store.append(sessionId, { role: "assistant", text, calls: [] });
|
|
654
|
+
emit("run_completed", { tokens: 0, text });
|
|
655
|
+
finish("completed");
|
|
656
|
+
return { runId, status: "completed", result };
|
|
657
|
+
}
|
|
658
|
+
catch (error) {
|
|
659
|
+
const cause = combined.aborted ? (combined.reason ?? error) : error;
|
|
660
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
661
|
+
emit(combined.aborted ? "run_cancelled" : "run_failed", { error: message });
|
|
662
|
+
finish(combined.aborted ? "cancelled" : "failed", message);
|
|
663
|
+
throw error;
|
|
664
|
+
}
|
|
665
|
+
finally {
|
|
666
|
+
if (acquired)
|
|
667
|
+
o.store.release(sessionId);
|
|
668
|
+
this.active.delete(sessionId);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
313
671
|
async run(sessionId, prompt, signal, options = {}) {
|
|
314
672
|
const controller = this.claim(sessionId);
|
|
315
673
|
const runId = options.runId ?? crypto.randomUUID();
|
|
@@ -394,6 +752,7 @@ export class AgentRunner {
|
|
|
394
752
|
text: prompt,
|
|
395
753
|
...(options.display ? { display: options.display } : {}),
|
|
396
754
|
...(options.attachments?.length ? { attachments: options.attachments } : {}),
|
|
755
|
+
...(options.datasets?.length ? { datasets: options.datasets } : {}),
|
|
397
756
|
});
|
|
398
757
|
emit("run_started", { model });
|
|
399
758
|
const budget = options.maxTokens ?? o.maxTokens ?? defaultTokenBudget(o.contextWindow?.(model));
|
|
@@ -407,7 +766,7 @@ export class AgentRunner {
|
|
|
407
766
|
o.store.append(sessionId, { role: "user", text: queued });
|
|
408
767
|
let instructions = await withPersona();
|
|
409
768
|
let messages = o.store.messages(sessionId);
|
|
410
|
-
const tools = this.availableTools(options);
|
|
769
|
+
const tools = this.availableTools(options, sessionId);
|
|
411
770
|
const toolsText = this.toolsText(tools);
|
|
412
771
|
const chars = () => instructions.length + JSON.stringify(messages).length + toolsText.length;
|
|
413
772
|
// REDUCIBLE content only (instructions + transcript). The fixed tool catalog
|
|
@@ -556,137 +915,36 @@ export class AgentRunner {
|
|
|
556
915
|
if (paths.length)
|
|
557
916
|
contextUpdate = await context.beforePaths(paths, sessionId);
|
|
558
917
|
let pendingUpdate = contextUpdate;
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
effect: p.tool?.effect ?? "external",
|
|
570
|
-
});
|
|
571
|
-
try {
|
|
572
|
-
combined.throwIfAborted();
|
|
573
|
-
if (p.error)
|
|
574
|
-
throw new Error(p.error);
|
|
575
|
-
if (!p.tool || !p.input)
|
|
576
|
-
throw new Error("Invalid tool");
|
|
577
|
-
const effect = p.tool.effect ?? "external";
|
|
578
|
-
// External-directory prerequisite: declared paths are resolved (and, outside every
|
|
579
|
-
// allowed root, approved for the containing directory) BEFORE the effect gate, so a
|
|
580
|
-
// write still needs its own write policy and a read never hard-throws first. The
|
|
581
|
-
// resolved map keeps "allow once" scoped to this one call, with no shared mutable
|
|
582
|
-
// state that parallel read batches could race on.
|
|
583
|
-
const resolved = new Map();
|
|
584
|
-
if (pathAccess)
|
|
585
|
-
for (const declared of p.tool.paths?.(p.input) ?? [])
|
|
586
|
-
if (!resolved.has(declared)) {
|
|
587
|
-
const target = await pathAccess.resolve(declared, {
|
|
588
|
-
workspace,
|
|
589
|
-
session: sessionId,
|
|
590
|
-
...(options.label ? { label: options.label } : {}),
|
|
591
|
-
signal: combined,
|
|
592
|
-
});
|
|
593
|
-
// Key both the declared input and its resolved form: a write resolves the
|
|
594
|
-
// input once, then re-checks the already-absolute path, and neither lookup may
|
|
595
|
-
// ask a second time for an "allow once" decision.
|
|
596
|
-
resolved.set(declared, target);
|
|
597
|
-
resolved.set(target, target);
|
|
598
|
-
}
|
|
918
|
+
const scope = {
|
|
919
|
+
sessionId,
|
|
920
|
+
runId,
|
|
921
|
+
emit,
|
|
922
|
+
signal: combined,
|
|
923
|
+
workspace,
|
|
924
|
+
policy,
|
|
925
|
+
approvals,
|
|
926
|
+
options,
|
|
927
|
+
guard: (effect) => {
|
|
599
928
|
if (contextUpdate && effect !== "read")
|
|
600
929
|
throw new Error(`Context changed; reconsider this call before retrying.\n${contextUpdate}`);
|
|
601
930
|
if (tokens >= budget)
|
|
602
931
|
throw new Error("Token budget exhausted; tool was not executed");
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
if (!
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
call,
|
|
618
|
-
effect,
|
|
619
|
-
input: p.input,
|
|
620
|
-
signal: combined,
|
|
621
|
-
session: sessionId,
|
|
622
|
-
...(options.label ? { label: options.label } : {}),
|
|
623
|
-
});
|
|
624
|
-
combined.throwIfAborted();
|
|
625
|
-
emit("approval_resolved", { id: call.id, name: call.name, effect, decision });
|
|
626
|
-
if (decision === "deny")
|
|
627
|
-
throw new Error(`Capability ${effect} denied by the user for this call`);
|
|
628
|
-
if (decision === "session")
|
|
629
|
-
policy[effect] = true;
|
|
630
|
-
}
|
|
631
|
-
o.store.beginCall(sessionId, call, { runId, effect });
|
|
632
|
-
result = await p.tool.execute(p.input, {
|
|
633
|
-
signal: combined,
|
|
634
|
-
workspace,
|
|
635
|
-
session: sessionId,
|
|
636
|
-
emit: (data) => emit("tool_progress", { id: call.id, data }),
|
|
637
|
-
...(options.label ? { label: options.label } : {}),
|
|
638
|
-
...(pathAccess
|
|
639
|
-
? {
|
|
640
|
-
resolvePath: (path) => {
|
|
641
|
-
const known = resolved.get(path);
|
|
642
|
-
return known !== undefined
|
|
643
|
-
? Promise.resolve(known)
|
|
644
|
-
: pathAccess.resolve(path, {
|
|
645
|
-
workspace,
|
|
646
|
-
session: sessionId,
|
|
647
|
-
...(options.label ? { label: options.label } : {}),
|
|
648
|
-
signal: combined,
|
|
649
|
-
});
|
|
650
|
-
},
|
|
651
|
-
}
|
|
652
|
-
: {}),
|
|
653
|
-
});
|
|
654
|
-
// The bound applies to what the model sees (the text projection): display-only
|
|
655
|
-
// ui/image parts are bounded by their producers and must not push text over it.
|
|
656
|
-
const projected = textProjection(result);
|
|
657
|
-
if (JSON.stringify(projected).length > 48_000)
|
|
658
|
-
result = textResult(`${JSON.stringify(projected).slice(0, 40_000)}\n[tool output truncated]`, result.isError);
|
|
659
|
-
if (pendingUpdate && effect === "read") {
|
|
660
|
-
result = {
|
|
661
|
-
...result,
|
|
662
|
-
content: [
|
|
663
|
-
...result.content,
|
|
664
|
-
{ type: "text", text: `\n<instructions>\n${pendingUpdate}\n</instructions>` },
|
|
665
|
-
],
|
|
666
|
-
};
|
|
667
|
-
pendingUpdate = undefined;
|
|
668
|
-
}
|
|
669
|
-
o.store.endCall(sessionId, call, result);
|
|
670
|
-
}
|
|
671
|
-
catch (error) {
|
|
672
|
-
result = textResult(error instanceof Error ? error.message : String(error), true);
|
|
673
|
-
// A cancellation after execution may have left effects; journal remains pending.
|
|
674
|
-
if (!combined.aborted)
|
|
675
|
-
o.store.endCall(sessionId, call, result);
|
|
676
|
-
}
|
|
677
|
-
emit("tool_completed", {
|
|
678
|
-
id: call.id,
|
|
679
|
-
name: call.name,
|
|
680
|
-
isError: result.isError ?? false,
|
|
681
|
-
durationMs: Date.now() - started,
|
|
682
|
-
preview: result.content
|
|
683
|
-
.filter((part) => part.type === "text")
|
|
684
|
-
.map((c) => c.text)
|
|
685
|
-
.join("\n")
|
|
686
|
-
.slice(0, 2_000),
|
|
687
|
-
});
|
|
688
|
-
return result;
|
|
932
|
+
},
|
|
933
|
+
amend: (result, effect) => {
|
|
934
|
+
if (!pendingUpdate || effect !== "read")
|
|
935
|
+
return result;
|
|
936
|
+
const update = pendingUpdate;
|
|
937
|
+
pendingUpdate = undefined;
|
|
938
|
+
return {
|
|
939
|
+
...result,
|
|
940
|
+
content: [
|
|
941
|
+
...result.content,
|
|
942
|
+
{ type: "text", text: `\n<instructions>\n${update}\n</instructions>` },
|
|
943
|
+
],
|
|
944
|
+
};
|
|
945
|
+
},
|
|
689
946
|
};
|
|
947
|
+
const execute = (p) => this.executeCall(scope, p);
|
|
690
948
|
const results = [];
|
|
691
949
|
// Bounded parallel batches for consecutive read or explicitly concurrent tools.
|
|
692
950
|
const parallel = (p) => !!p?.tool && (p.tool.effect === "read" || p.tool.concurrent === true);
|
package/dist/index.d.ts
CHANGED
|
@@ -7,11 +7,26 @@ export { AGENT_ID_PATTERN, AGENT_LIMITS, AGENT_REASONING_SUMMARIES, AGENT_TEXT_F
|
|
|
7
7
|
export { AGENT_DRAFT_INSTRUCTIONS, AGENT_DRAFT_MAX_DESCRIPTION, type AgentAuthoringGuidance, agentAuthoringGuidance, agentDraftRequest, generateAgentDraft, parseAgentDraft, } from "./agents/draft.ts";
|
|
8
8
|
export { type AgentChange, AgentDefinitionService, type AgentDefinitionServiceOptions, type AgentRegistry, mergeAgentScopes, } from "./agents/service.ts";
|
|
9
9
|
export { AGENT_TEMPLATES, agentTemplate } from "./agents/templates.ts";
|
|
10
|
+
export { CapabilityGrants, type GrantRecord, type GrantSource, toGrantWire, } from "./analysis/capabilities.ts";
|
|
11
|
+
export { CsvParser, decodeTextBytes, detectDelimiter } from "./analysis/data/csv.ts";
|
|
12
|
+
export { type DatasetLimits, type DatasetRecord, DatasetService, DEFAULT_DATASET_LIMITS, datasetFormat, PageParamError, toDatasetRef, XLSX_REMEDY, } from "./analysis/data/datasets.ts";
|
|
13
|
+
export { DataEngine, DataError, type DataErrorCode, } from "./analysis/data/engine-client.ts";
|
|
14
|
+
export { guardSql } from "./analysis/data/sql-guard.ts";
|
|
15
|
+
export { detectHintHost, type HintHost, type InstallHints, installHintsMarkdown, installHintsText, parseOsRelease, pythonInstallHints, } from "./analysis/install-hints.ts";
|
|
16
|
+
export { AnalysisJanitor, type RetentionPolicy, SWEEP_INTERVAL_MS, type SweepReport, } from "./analysis/janitor.ts";
|
|
17
|
+
export { AnalysisJobs, type ExecutionDetails, type ExecutionStatus, type JobPaths, } from "./analysis/jobs.ts";
|
|
18
|
+
export { containerName, type OciDeps, type OciEngine, OciRuntime, type OciSettings, type OciStatus, ociRunArgs, parseDigests, } from "./analysis/oci.ts";
|
|
19
|
+
export { AnalysisRerun, type RerunPlan, type RerunPreparation, } from "./analysis/rerun.ts";
|
|
20
|
+
export { AnalysisRuntimeManager, type DiscoveryDeps, type Extras, ExtrasInstallError, type InstallStep, installPreview, type PythonCandidate, type PythonResolution, type RuntimeState, setupCommand, venvInterpreter, } from "./analysis/runtime-manager.ts";
|
|
21
|
+
export { analysisStatus } from "./analysis/status.ts";
|
|
10
22
|
export { type AppOptions, type BuiltinContext, type BuiltinPlugin, createApplication, enabledBuiltins, type PluginCatalogEntry, type PluginCatalogStatus, } from "./application.ts";
|
|
23
|
+
export { classifyArtifact, extensionOf, fileType as artifactFileType, isPreviewable, KIND_LABELS, viewerContentType, } from "./artifacts/kinds.ts";
|
|
24
|
+
export { createArtifactPublisher } from "./artifacts/publisher.ts";
|
|
25
|
+
export { type ArtifactFile, type ArtifactLimits, type ArtifactOwner, type ArtifactRecord, ArtifactRejected, ArtifactStore, type PublishedArtifact, readHead as readArtifactHead, slugify as artifactSlug, toRef, } from "./artifacts/store.ts";
|
|
11
26
|
export { BUILTIN_COMMANDS, type BuiltinCommand, CommandCatalog, type CommandExecutionContext, type CommandHost, type CommandResult, type CommandSurface, } from "./commands/catalog.ts";
|
|
12
|
-
export { type Config, type ConfigLoadResult, type ConfigProvenance, configFile, configHome, configSchema, isSettableSettingKey, type LoadedConfig, loadConfig, loadConfigWithProvenance, type McpServerSource, overridesSavedProviderProfile, type SettableSettingInfo, type SettableSettingKey, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, settableSettings, stateHome, } from "./config.ts";
|
|
27
|
+
export { type Config, type ConfigLoadResult, type ConfigProvenance, configFile, configHome, configSchema, isSettableSettingKey, type LoadedConfig, loadConfig, loadConfigWithProvenance, type McpServerSource, OCI_IMAGE_PATTERN, overridesSavedProviderProfile, type SettableSettingInfo, type SettableSettingKey, setConfigValue, setGlobalMcpAllow, setMcpServerEnabled, setProjectPluginEnabled, setProjectSkillEnabled, settableSettings, stateHome, } from "./config.ts";
|
|
13
28
|
export { type ContextBudget, checkpointInstructions, completeText, effectiveContextBudget, estimateTokens, MAX_TRUSTED_WINDOW, parseCheckpointOutput, planCompaction, renderCheckpoint, serializeForSummary, shouldCompact, shouldCompactContext, summarize, } from "./core/compaction.ts";
|
|
14
|
-
export type { ApprovalDecision, ApprovalHandler, ApprovalRequest, BeginRunInput, ContextSource, EndRunInput, EventPage, HookFailure, MessagePage, PageOptions, Policy, RunnerExtensions, RunRecord, RunStatus, Session, SessionStore, StoredEvent, TerminalRunStatus, ToolCallMeta, } from "./core/contracts.ts";
|
|
29
|
+
export type { ApprovalDecision, ApprovalHandler, ApprovalRequest, ArtifactPublisherFactory, BeginRunInput, CapabilityGate, ContextSource, CoreArtifactPublisher, EndRunInput, EventPage, HookFailure, MessagePage, PageOptions, Policy, PublishedArtifactInfo, RunnerExtensions, RunRecord, RunStatus, Session, SessionStore, StoredEvent, TerminalRunStatus, ToolCallMeta, } from "./core/contracts.ts";
|
|
15
30
|
export { ToolRegistry } from "./core/registry.ts";
|
|
16
31
|
export { AgentRunner, type CompactionResult, defaultTokenBudget, type RunnerOptions, type RunnerSettingsPatch, type RunOptions, } from "./core/runner.ts";
|
|
17
32
|
export { type ExtensionConflict, ExtensionRegistry } from "./extensions/registry.ts";
|
|
@@ -26,16 +41,20 @@ export { type InstructionFile, ProjectContext, type ProjectContextOptions, } fro
|
|
|
26
41
|
export { expandSlashPrompt, loadPromptTemplates, type PromptDiagnostic, type PromptRequirement, type PromptSource, type PromptSourceKind, type PromptTemplate, parsePromptTemplate, promptSources, renderPromptTemplate, splitArguments, } from "./resources/prompts.ts";
|
|
27
42
|
export { type Skill, type SkillCatalogEntry, type SkillRoot, type SkillScope, Skills, skillRoots, } from "./resources/skills.ts";
|
|
28
43
|
export { type ExternalDirectoryDecision, type ExternalDirectoryHandler, type ExternalDirectoryRequest, PathAccess, type PathAccessOptions, type ResolvePathOptions, } from "./runtime/access.ts";
|
|
29
|
-
export { BlobStore, type BlobStoreOptions } from "./runtime/blobs.ts";
|
|
44
|
+
export { BlobStore, type BlobStoreOptions, BlobTooLarge } from "./runtime/blobs.ts";
|
|
30
45
|
export { clipLines, unifiedPatch } from "./runtime/diff.ts";
|
|
31
46
|
export { exists, fileSize, readHead, readJson, readText, which } from "./runtime/fs.ts";
|
|
47
|
+
export { newId, ulid } from "./runtime/ids.ts";
|
|
32
48
|
export { defaultGlobalRoots, isPathSpec, PLUGIN_KEYWORD, resolvePluginSpec, } from "./runtime/modules.ts";
|
|
33
|
-
export { findWorkspace, inside, outsideRootsMessage, safePath } from "./runtime/paths.ts";
|
|
49
|
+
export { findWorkspace, inside, outsideRootsMessage, safePath, workspaceKey, } from "./runtime/paths.ts";
|
|
34
50
|
export { isMissingCommand, type ProcessResult, RIPGREP_INSTALL_HINT, runProcess, } from "./runtime/process.ts";
|
|
35
51
|
export { isSqliteExperimentalWarning, openDatabase } from "./runtime/sqlite.ts";
|
|
36
52
|
export { SQLiteStore } from "./runtime/store.ts";
|
|
53
|
+
export { crc32, writeZip, type ZipEntry, type ZipSink } from "./runtime/zip.ts";
|
|
37
54
|
export { ChildSessions, type ChildSessionsOptions } from "./sessions/children.ts";
|
|
38
55
|
export { formatSideQuestion, SIDE_QUESTION_DESCRIPTION, SIDE_QUESTION_HISTORY_LIMIT, SIDE_QUESTION_INSTRUCTIONS, SIDE_QUESTION_MAX_CHARS, SIDE_QUESTION_USAGE, SIDE_QUESTIONS_NAMESPACE, type SideQuestionEntry, SideQuestions, type SideQuestionsOptions, sideTranscript, } from "./sessions/side-questions.ts";
|
|
39
56
|
export { composeSideBySide, DefaultAlisioMascot, DefaultStartupScreen, infoSection, mascotSection, padEnd, pluginsSection, renderStartup, type StartupDiagnostic, type StartupInput, type StartupResult, sanitizeLine, shortenPath, startupTips, stripAnsi, tipsSection, titleSection, truncate, visibleWidth, welcomeSection, } from "./startup/index.ts";
|
|
57
|
+
export { formatBytes, NOT_SANDBOXED } from "./tools/analysis.ts";
|
|
58
|
+
export { ARTIFACT_READ_MAX, exportedPaths } from "./tools/artifacts.ts";
|
|
40
59
|
export { hash, objectSchema, registerStandard } from "./tools/standard.ts";
|
|
41
60
|
export { getTrust, hashProjectConfig, hasProjectResources, listTrust, resolveTrust, revokeTrust, setTrust, type TrustEntry, type TrustListing, type TrustResolution, trustStorePath, } from "./trust.ts";
|