@hachej/boring-agent 0.1.95 → 0.1.96

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.
Files changed (45) hide show
  1. package/dist/DebugDrawer-2TO5SE2D.js +7 -0
  2. package/dist/{chunk-NITBKFG6.js → chunk-3OEDBRKY.js} +93 -58
  3. package/dist/{chunk-BOIV2I3N.js → chunk-46HJK2ES.js} +31 -16
  4. package/dist/{chunk-AQBXNPMD.js → chunk-4IQ4HHBG.js} +4 -0
  5. package/dist/{chunk-OFQ7J6SI.js → chunk-LSO2AO6Q.js} +57 -1
  6. package/dist/{chunk-2EMAKBVR.js → chunk-NSE2RHU3.js} +8967 -7740
  7. package/dist/{chunk-2GBHYJVC.js → chunk-VXF5DWS6.js} +34 -0
  8. package/dist/{chunk-2TMS2RU2.js → chunk-WC5KBGP2.js} +518 -165
  9. package/dist/chunk-YGRQ4Q5P.js +20 -0
  10. package/dist/core/index.d.ts +5 -5
  11. package/dist/core/index.js +604 -7
  12. package/dist/{createHarness-UCD74XXK.js → createHarness-PW3A2MRB.js} +3 -3
  13. package/dist/{errors-G6T6S7PQ.d.ts → errors-cNC4HMpV.d.ts} +14 -7
  14. package/dist/eval/index.d.ts +5 -3
  15. package/dist/eval/index.js +31 -23
  16. package/dist/file-search-QxnanNjO.d.ts +87 -0
  17. package/dist/front/index.d.ts +84 -16
  18. package/dist/front/index.js +832 -339
  19. package/dist/front/styles.css +1171 -2129
  20. package/dist/{harness-Cc48o6uS.d.ts → harness-DS8jLKIx.d.ts} +4 -2
  21. package/dist/{lease-CusB-uLg.d.ts → lease-D8WC6pQl.d.ts} +10 -89
  22. package/dist/{middleware-CzW8n7B7.d.ts → middleware-Cq_cYHjJ.d.ts} +1 -1
  23. package/dist/piChatEvent-B3ehh9V0.d.ts +384 -0
  24. package/dist/{piChatSessionService-C0KbcGw9.d.ts → piChatSessionService-xnv8rcdh.d.ts} +1 -1
  25. package/dist/{sandbox-DAD8cWQR.d.ts → sandbox-KQiEdz4W.d.ts} +12 -1
  26. package/dist/server/agent-host/testing/compositionRouteProof.d.ts +8 -0
  27. package/dist/server/agent-host/testing/compositionRouteProof.js +78 -0
  28. package/dist/server/agent-host/testing/gatewayConformance.d.ts +6 -6
  29. package/dist/server/agent-host/testing/gatewayConformance.js +17 -9
  30. package/dist/server/index.d.ts +569 -370
  31. package/dist/server/index.js +69 -17
  32. package/dist/server/worker/index.d.ts +2 -2
  33. package/dist/server/worker/index.js +9 -9
  34. package/dist/shared/index.d.ts +212 -56
  35. package/dist/shared/index.js +43 -7
  36. package/dist/{types-C-Eroi__.d.ts → types-D_SD-7_l.d.ts} +304 -87
  37. package/docs/AGENT_GATEWAY_V0.md +6 -3
  38. package/docs/AGENT_PACKAGES.md +80 -0
  39. package/docs/ERROR_CODES.md +58 -0
  40. package/docs/README.md +1 -0
  41. package/docs/runtime.md +19 -2
  42. package/package.json +34 -29
  43. package/dist/DebugDrawer-RYEBQ6CO.js +0 -6
  44. package/dist/chunk-EOMY2HDT.js +0 -619
  45. package/dist/piChatEvent-BsMp3MSo.d.ts +0 -368
@@ -1,13 +1,77 @@
1
- import * as fastify from 'fastify';
2
1
  import { FastifyRequest, FastifyPluginAsync } from 'fastify';
3
- import { w as ToolReadinessRequirement, T as TelemetrySink, b as Agent, A as AgentHarness, t as AgentTool, u as AgentHarnessFactory } from './harness-Cc48o6uS.js';
4
- import { F as FileSearch, b as AgentSessionRef, V as VerifiedAgentScopeClaim, g as AgentGatewayErrorDTO, J as JsonValue, a as AuthorizedAgentScope, A as AgentGateway, h as AgentScopeVerifier } from './errors-G6T6S7PQ.js';
5
- import { o as ChatModelSelection } from './piChatEvent-BsMp3MSo.js';
6
- import { b as Workspace, c as WorkspaceRuntimeContext, S as Sandbox } from './sandbox-DAD8cWQR.js';
7
- import { RuntimeHostOperations } from '@hachej/boring-bash/agent';
2
+ import { w as ToolReadinessRequirement, T as TelemetrySink, s as AgentTool, t as AgentHarnessFactory } from './harness-DS8jLKIx.js';
3
+ import { F as FileSearch, A as AgentSkillResource, W as WorkspaceAgentDirectRunInput, L as LeaseBoundWorkspaceAgent } from './file-search-QxnanNjO.js';
4
+ import { b as Workspace, R as RuntimeFilesystemCapability, c as WorkspaceRuntimeContext, S as Sandbox } from './sandbox-KQiEdz4W.js';
5
+ import { d as AgentSessionRef, V as VerifiedAgentScopeClaim, f as AgentGatewayErrorDTO, J as JsonValue, c as AuthorizedAgentScope, b as AgentGateway, j as AgentScopeVerifier } from './errors-cNC4HMpV.js';
6
+ import { o as ChatModelSelection } from './piChatEvent-B3ehh9V0.js';
7
+ import { RuntimeHostOperations, RuntimeFilesystemBinding as RuntimeFilesystemBinding$1 } from '@hachej/boring-bash/agent';
8
8
  import { CreateNodeWorkspaceOptions, BoringAgentRuntimePaths } from '@hachej/boring-sandbox/providers/node-workspace';
9
- import { PackageSource, ExtensionFactory, SettingsManager } from '@mariozechner/pi-coding-agent';
10
- import { A as AgentCoreSessionService, g as PiChatSessionService } from './piChatSessionService-C0KbcGw9.js';
9
+ import { PackageSource, ExtensionFactory } from '@mariozechner/pi-coding-agent';
10
+
11
+ type SessionFileChangeOp = 'write' | 'edit' | 'unlink' | 'rename' | 'mkdir';
12
+ interface SessionFileChange {
13
+ op: SessionFileChangeOp;
14
+ path: string;
15
+ oldPath?: string;
16
+ size?: number;
17
+ timestamp: string;
18
+ }
19
+ interface SessionChangesTracker {
20
+ record(scope: SessionChangesScope | string, change: SessionFileChange): void;
21
+ list(scope: SessionChangesScope | string): SessionFileChange[];
22
+ clear(scope: SessionChangesScope | string): void;
23
+ }
24
+ interface SessionChangesScope {
25
+ readonly workspaceScopeId?: string;
26
+ readonly agentTypeId?: string;
27
+ readonly sessionId: string;
28
+ }
29
+
30
+ interface AgentModelSelection {
31
+ provider: string;
32
+ id: string;
33
+ }
34
+
35
+ /**
36
+ * GET /api/v1/agents/:agentTypeId/models
37
+ *
38
+ * Returns the list of models pi-coding-agent has auth for (i.e. where
39
+ * the corresponding provider API key is present in the environment or
40
+ * `~/.pi/agent/auth.json`). Consumers — including the shadcn example
41
+ * ChatPanel — fetch this endpoint to populate the model-selector dropdown
42
+ * instead of hardcoding a short alias list.
43
+ *
44
+ * Shape:
45
+ * {
46
+ * models: [
47
+ * { provider: "anthropic", id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", available: true },
48
+ * ...
49
+ * ]
50
+ * }
51
+ *
52
+ * Safe to call unauthenticated — we only report {provider, id, label,
53
+ * available}, never any key material.
54
+ */
55
+
56
+ interface ModelSummary {
57
+ provider: string;
58
+ id: string;
59
+ label: string;
60
+ available: boolean;
61
+ }
62
+ interface ModelFilterContext {
63
+ request: FastifyRequest;
64
+ workspaceId?: string;
65
+ }
66
+ type ModelFilterResult = {
67
+ models: readonly ModelSummary[];
68
+ defaultModel?: AgentModelSelection;
69
+ };
70
+ interface ModelsRoutesOptions {
71
+ path?: string;
72
+ authorizeRequest?: (request: FastifyRequest) => void | Promise<void>;
73
+ filterModels?: (ctx: ModelFilterContext, models: readonly ModelSummary[], defaultModel: AgentModelSelection | undefined) => ModelFilterResult | Promise<ModelFilterResult>;
74
+ }
11
75
 
12
76
  /**
13
77
  * Generic metering seam for hosts that bill native Pi usage.
@@ -187,7 +251,13 @@ interface AgentRuntimeHostOperations extends RuntimeHostOperations {
187
251
  }>;
188
252
  validatePath(root: string, requestedPath: string): string;
189
253
  assertRealPathWithinWorkspace(root: string, targetPath: string): Promise<void>;
254
+ resolveRealWorkspacePath(root: string, targetPath: string): Promise<string>;
190
255
  isIgnoredDirName(name: string): boolean;
256
+ /** Host-owned confined projection for package resources outside the workspace. */
257
+ createAgentResourceFilesystemBinding(filesystem: string, mounts: readonly {
258
+ readonly logicalRoot: string;
259
+ readonly sourceRoot: string;
260
+ }[]): Promise<RuntimeFilesystemBinding$1>;
191
261
  }
192
262
 
193
263
  interface ProvisioningLogger {
@@ -243,7 +313,7 @@ interface ResolveInstallSourceOpts {
243
313
  fingerprint: string;
244
314
  }
245
315
  interface WorkspaceProvisioningAdapter {
246
- mode: 'direct' | 'local' | 'vercel-sandbox';
316
+ mode: 'direct' | 'local' | 'blaxel' | 'vercel-sandbox';
247
317
  exec(command: string, args: string[], opts?: {
248
318
  cwd?: string;
249
319
  env?: Record<string, string>;
@@ -283,7 +353,7 @@ interface ProvisionWorkspaceRuntimeOptions {
283
353
  telemetryContext?: ProvisioningTelemetryContext;
284
354
  }
285
355
 
286
- type BuiltinRuntimeModeId = 'direct' | 'local' | 'vercel-sandbox';
356
+ type BuiltinRuntimeModeId = 'direct' | 'local' | 'blaxel' | 'vercel-sandbox';
287
357
  type RuntimeModeId = BuiltinRuntimeModeId | (string & {});
288
358
  interface RuntimeModeReadinessHooks {
289
359
  initialSandboxReady?: boolean;
@@ -352,6 +422,12 @@ interface ModeContext {
352
422
  requestId?: string;
353
423
  telemetry?: TelemetrySink;
354
424
  }
425
+ interface RuntimeFilesystemAccessDecision {
426
+ readonly filesystem: string;
427
+ readonly normalizedPath: string;
428
+ readonly access: 'readonly' | 'readwrite';
429
+ readonly capabilities: Readonly<Record<RuntimeFilesystemCapability, boolean>>;
430
+ }
355
431
  interface RuntimeFilesystemBindingOperations {
356
432
  read(descriptor: {
357
433
  filesystem: string;
@@ -408,6 +484,14 @@ interface RuntimeFilesystemBindingOperations {
408
484
  mtimeMs?: number;
409
485
  metadata?: unknown;
410
486
  }>;
487
+ writeBinary?(descriptor: {
488
+ filesystem: string;
489
+ path: string;
490
+ content: Uint8Array;
491
+ }): Promise<{
492
+ mtimeMs?: number;
493
+ metadata?: unknown;
494
+ }>;
411
495
  delete?(descriptor: {
412
496
  filesystem: string;
413
497
  path: string;
@@ -428,6 +512,10 @@ interface RuntimeFilesystemBindingOperations {
428
512
  }): Promise<{
429
513
  metadata?: unknown;
430
514
  }>;
515
+ resolveAccess?(descriptor: {
516
+ filesystem: string;
517
+ path: string;
518
+ }): Promise<RuntimeFilesystemAccessDecision>;
431
519
  rejectMutation(operation: string, descriptor: {
432
520
  filesystem: string;
433
521
  path: string;
@@ -459,6 +547,12 @@ interface RuntimeBundle {
459
547
  filesystem?: RuntimeFilesystemStrategy;
460
548
  /** Optional filesystem bindings prepared for this runtime/session. */
461
549
  filesystemBindings?: RuntimeFilesystemBinding[];
550
+ /**
551
+ * Workspace-relative prefixes the host protects from mutation. Carried on the
552
+ * bundle so shell/provisioning enforcement uses the same policy as the
553
+ * Operations bindings instead of re-deriving it.
554
+ */
555
+ readonlyWorkspacePaths?: readonly string[];
462
556
  /** Provisioning operations derived from this bundle's acquired Workspace + Sandbox pair. */
463
557
  provisioningAdapter?: WorkspaceProvisioningAdapter;
464
558
  /** Idempotently releases the acquired Workspace + Sandbox pair. */
@@ -474,6 +568,8 @@ declare function mergePiPackageSources(base?: PiPackageSource[], additional?: Pi
474
568
  interface PiHarnessOptions {
475
569
  noContextFiles?: boolean;
476
570
  noSkills?: boolean;
571
+ /** Disable ambient Pi extensions (required when tools execute in a remote runtime). */
572
+ noExtensions?: boolean;
477
573
  additionalSkillPaths?: string[];
478
574
  defaultModel?: {
479
575
  provider: string;
@@ -510,9 +606,36 @@ interface HotReloadablePiResources {
510
606
  extensionPaths?: string[];
511
607
  }
512
608
  type PiExtensionFactory = ExtensionFactory;
513
- declare function createResourceSettingsManager(cwd: string, agentDir: string, piPackages: PiPackageSource[]): SettingsManager;
514
609
 
515
- type AgentGatewayEffect = 'session.create' | 'session.rename' | 'session.delete' | 'session.prompt' | 'session.followup' | 'session.interrupt' | 'session.stop' | 'session.queue.clear';
610
+ /**
611
+ * GET /api/v1/agents/:agentTypeId/skills
612
+ *
613
+ * Returns the list of PI skills discovered for the current workspace —
614
+ * global skills (~/.pi/agent/skills) plus any project-local SKILL.md files.
615
+ * The front-end uses this to populate the slash-command picker without
616
+ * host apps having to hardcode skill names in extraCommands.
617
+ *
618
+ * Shape:
619
+ * { skills: [{ name: string, description: string }] }
620
+ */
621
+
622
+ interface SkillSummary {
623
+ name: string;
624
+ description: string;
625
+ /** Browser-safe locator for opening a supported skill source. */
626
+ resource?: AgentSkillResource;
627
+ /** False for management-only rows that Pi did not retain as invocable. */
628
+ invocable?: boolean;
629
+ /** Human-readable source/scope label for diagnostics and disabled rows. */
630
+ source?: string;
631
+ }
632
+ interface AgentSkillResourceSnapshot {
633
+ readonly generation: string;
634
+ readonly managedSkills: readonly SkillSummary[];
635
+ locateSkill(filePath: string): AgentSkillResource | undefined;
636
+ }
637
+
638
+ type AgentGatewayEffect = 'session.create' | 'session.rename' | 'session.delete' | 'session.prompt' | 'session.followup' | 'session.interrupt' | 'session.stop' | 'session.queue.clear' | 'agent.reload' | 'session.command.execute';
516
639
  type AgentRequestTarget = {
517
640
  readonly kind: 'agent';
518
641
  readonly agentTypeId: string;
@@ -527,25 +650,20 @@ interface AgentRequestKey {
527
650
  readonly target: AgentRequestTarget;
528
651
  readonly requestId: string;
529
652
  }
653
+ interface AgentStableServiceErrorDTO {
654
+ readonly statusCode: number;
655
+ readonly error: {
656
+ readonly code: string;
657
+ readonly message: string;
658
+ readonly retryable?: boolean;
659
+ };
660
+ }
530
661
  type AgentRequestFailure = {
531
662
  readonly kind: 'gateway';
532
663
  readonly error: AgentGatewayErrorDTO;
533
664
  } | {
534
- /** Server-only compatibility envelope; never returned by AgentGateway. */
535
- readonly kind: 'legacy-admission';
536
- readonly code: string;
537
- readonly statusCode: 500;
538
- readonly message: string;
539
- readonly details?: JsonValue;
540
- } | {
541
- /** Server-only observed legacy service failure; never returned by AgentGateway. */
542
- readonly kind: 'legacy-service';
543
- readonly name: string;
544
- readonly message: string;
545
- readonly code?: string;
546
- readonly statusCode?: number;
547
- readonly retryable?: boolean;
548
- readonly details?: JsonValue;
665
+ readonly kind: 'service';
666
+ readonly error: AgentStableServiceErrorDTO;
549
667
  };
550
668
  interface AgentRequestLedgerRecordBase {
551
669
  readonly key: AgentRequestKey;
@@ -570,13 +688,22 @@ type AgentRequestLedgerRecord = (AgentRequestLedgerRecordBase & {
570
688
  readonly error: AgentGatewayErrorDTO;
571
689
  });
572
690
  interface AgentRequestLedger {
573
- prepare(key: AgentRequestKey, digest: string): Promise<AgentRequestLedgerRecord>;
691
+ /** Direct production projections require transactional durable ownership. */
692
+ readonly durability: 'durable-transactional' | 'in-memory';
693
+ /** Atomic compare-and-create across every process sharing the durable store. */
694
+ prepare(key: AgentRequestKey, digest: string): Promise<AgentRequestLedgerPrepareResult>;
695
+ /** All transitions are compare-and-swap against the exact allowed prior state. */
574
696
  acceptAdmission(key: AgentRequestKey, admissionReceipt: string): Promise<void>;
575
697
  beginEffect(key: AgentRequestKey): Promise<void>;
576
698
  reject(key: AgentRequestKey, failure: AgentRequestFailure): Promise<void>;
577
699
  complete(key: AgentRequestKey, receipt: JsonValue): Promise<void>;
578
700
  markOutcomeUnknown(key: AgentRequestKey, error: AgentGatewayErrorDTO): Promise<void>;
579
701
  read(key: AgentRequestKey): Promise<AgentRequestLedgerRecord | undefined>;
702
+ close?(): void | Promise<void>;
703
+ }
704
+ interface AgentRequestLedgerPrepareResult {
705
+ readonly ownership: 'created' | 'existing';
706
+ readonly record: AgentRequestLedgerRecord;
580
707
  }
581
708
  type AgentEffectAdmissionResult = {
582
709
  readonly type: 'accepted';
@@ -598,13 +725,45 @@ interface AgentEffectAdmission {
598
725
  readonly target: AgentRequestTarget;
599
726
  }): Promise<AgentEffectAdmissionResult>;
600
727
  }
728
+ /**
729
+ * An authored file that contributes to this agent's instructions, addressed
730
+ * exactly like every other openable resource (`{filesystem, path}`) so the
731
+ * client can route it through the same safety guard as skills.
732
+ *
733
+ * The Host knows these locations from fleet configuration; clients must never
734
+ * re-derive them from the agent id (seat and agentTypeId are unrelated
735
+ * fleet.yaml fields). `role` is a DISCRIMINATOR, not a display string — the
736
+ * words shown to the user are the client's business.
737
+ */
738
+ interface AgentInstructionFileRef {
739
+ readonly filesystem: string;
740
+ /** Workspace-relative path, e.g. `.agents/personas/concierge/instructions.md`. */
741
+ readonly path: string;
742
+ readonly role: 'persona';
743
+ }
601
744
  interface ConfiguredAgentHostAgentSpec {
602
745
  readonly agentTypeId: string;
603
746
  readonly definition: {
604
747
  readonly instructions: string;
605
748
  readonly label: string;
606
749
  readonly version?: string;
750
+ /**
751
+ * Computed identity of the compiled definition (instructions + knowledge
752
+ * bytes). The digest, not the version string, is the definition identity.
753
+ */
754
+ readonly digest?: string;
607
755
  };
756
+ /**
757
+ * Optional agent-carried knowledge shipped inside the definition package.
758
+ * Composition mounts it as a readonly, agent-scoped filesystem binding;
759
+ * absent = no binding.
760
+ */
761
+ readonly knowledge?: {
762
+ /** Host path of the package's `knowledge/` folder. */
763
+ readonly rootDir: string;
764
+ };
765
+ /** Authored instruction sources behind `definition.instructions`. */
766
+ readonly instructionFiles?: readonly AgentInstructionFileRef[];
608
767
  readonly plugins?: readonly {
609
768
  /** Canonical app-preflighted plugin ID. */
610
769
  readonly name: string;
@@ -638,6 +797,8 @@ interface AgentFleetCompiler {
638
797
  interface ResolvedEnvironmentScope {
639
798
  readonly placementIdentity: string;
640
799
  readonly workspaceRoot: string;
800
+ /** Physical provider workspace identifier; defaults to the verified storage scope. */
801
+ readonly runtimeWorkspaceId?: string;
641
802
  readonly templatePath?: string;
642
803
  readonly provisioningFingerprint: string;
643
804
  readonly provisionRuntime?: (input: {
@@ -646,81 +807,116 @@ interface ResolvedEnvironmentScope {
646
807
  }) => Promise<WorkspaceProvisioningResult | undefined>;
647
808
  }
648
809
  interface ResolvedAgentRuntimeScope {
649
- /** Complete app-canonicalized PL1 composition identity. */
810
+ /** Persisted semantic compatibility identity. */
650
811
  readonly identity: string;
812
+ /** Stable physical binding slot, independent of semantic resource revisions. */
813
+ readonly physicalBindingIdentity?: string;
814
+ /** Canonical digest of the immutable plugin/resource inputs used by reload. */
815
+ readonly resourceInputDigest?: string;
816
+ /**
817
+ * Side-effect-free fence for path-backed reload resources. The Host invokes
818
+ * it after classification, immediately before the effect, and after every
819
+ * awaited apply/load stage so a successful receipt always matches the
820
+ * resourceInputDigest recorded in the ledger.
821
+ */
822
+ readonly revalidateResourceInputs?: () => Promise<void>;
651
823
  readonly environment: ResolvedEnvironmentScope;
652
824
  readonly sessionNamespace: string;
653
825
  readonly pi?: PiHarnessOptions;
654
826
  readonly extraTools?: readonly AgentTool[];
827
+ readonly includeFilesystemTools?: boolean;
828
+ readonly includeUploadTools?: boolean;
829
+ readonly sessionDir?: string;
830
+ readonly reloadMetadata?: {
831
+ readonly diagnostics?: ReadonlyArray<{
832
+ readonly source: string;
833
+ readonly message: string;
834
+ readonly pluginId?: string;
835
+ }>;
836
+ readonly restartWarnings?: ReadonlyArray<{
837
+ readonly id: string;
838
+ readonly surfaces: readonly string[];
839
+ readonly message: string;
840
+ }>;
841
+ };
842
+ /**
843
+ * Host-internal reload mutation. Candidate identity fields above must be
844
+ * resolved without mutating plugin, backend, or runtime resource state.
845
+ * The Host invokes this callback only after durable ownership, admission,
846
+ * immutable identity classification, and the binding operation fence.
847
+ */
848
+ readonly applyReload?: (input: {
849
+ readonly runtimeBundle: RuntimeBundle;
850
+ }) => Promise<{
851
+ readonly diagnostics?: ReadonlyArray<{
852
+ readonly source: string;
853
+ readonly message: string;
854
+ readonly pluginId?: string;
855
+ }>;
856
+ readonly restartWarnings?: ReadonlyArray<{
857
+ readonly id: string;
858
+ readonly surfaces: readonly string[];
859
+ readonly message: string;
860
+ }>;
861
+ } | undefined>;
655
862
  readonly getFilesystemBindings?: (input: {
656
863
  readonly scope: VerifiedAgentScopeClaim;
657
864
  readonly sessionId?: string;
658
865
  readonly requestId: string;
659
866
  }) => Promise<readonly RuntimeFilesystemBinding[] | undefined>;
867
+ /**
868
+ * Skill-resource locator/catalog snapshot for the current reload
869
+ * generation. Threaded through the capability-projection layer so
870
+ * `/skills` can resolve package-managed skill locators without going
871
+ * through the legacy path-shaped `additionalSkillPaths` hot-reload API.
872
+ */
873
+ readonly getSkillResourceSnapshot?: (input: {
874
+ readonly scope: VerifiedAgentScopeClaim;
875
+ readonly sessionId?: string;
876
+ readonly requestId: string;
877
+ }) => Promise<AgentSkillResourceSnapshot | undefined>;
660
878
  readonly systemPromptAppend?: string;
661
879
  readonly loadSystemPromptAppend?: () => Promise<string | undefined>;
662
880
  }
663
- interface AgentHostLegacyProjectionComposition {
664
- readonly agent: Agent;
665
- readonly harness: AgentHarness;
666
- readonly service: AgentCoreSessionService;
667
- readonly tools: readonly AgentTool[];
668
- readonly runtimeBundle: RuntimeBundle;
669
- readonly readyTracker: ReadyStatusTracker;
670
- retire(): Promise<void>;
671
- }
672
- /** Narrow Host-owned facade used only while mounting the compatibility profile. */
673
- interface AgentHostLegacyProjectionRuntime {
674
- readonly gateway: AgentGateway;
675
- resolveComposition(agentTypeId: string, scope: AuthorizedAgentScope): Promise<AgentHostLegacyProjectionComposition>;
676
- createAddressedRoutes(options: {
677
- readonly authorizeRequest: (request: FastifyRequest) => Promise<AuthorizedAgentScope>;
678
- readonly defaultAgentTypeId: string;
679
- }): FastifyPluginAsync;
680
- createPiChatService(input: {
681
- readonly service: AgentCoreSessionService;
682
- readonly scope: AuthorizedAgentScope;
683
- readonly agentTypeId: string;
684
- }): PiChatSessionService;
685
- }
686
- interface AgentHostLegacyProjectionLifecycle {
687
- startDraining(): void;
688
- closeBindings(): Promise<void>;
689
- }
690
- interface AgentHostLegacyRoutePolicyMountInput {
691
- readonly app: fastify.FastifyInstance;
692
- readonly runtime: AgentHostLegacyProjectionRuntime;
693
- readonly defaultAgentTypeId: string;
694
- registerLifecycle(lifecycle: AgentHostLegacyProjectionLifecycle): void;
881
+ interface AuthorizedEnvironmentIntent {
882
+ readonly kind: 'http-route' | 'dispatcher' | 'agent-binding';
883
+ readonly requestId: string;
695
884
  }
696
- /**
697
- * Normalized legacy/application route profile mounted only through the Host.
698
- * Omission keeps the addressed-only HTTP projection.
699
- */
700
- interface AgentHostLegacyRoutePolicy {
701
- mount(input: AgentHostLegacyRoutePolicyMountInput): Promise<void>;
885
+ interface AgentHostEnvironmentScope extends ResolvedEnvironmentScope {
886
+ /** App-owned environment decoration applied once to the canonical provider generation. */
887
+ readonly transformRuntimeBundle?: (runtimeBundle: RuntimeBundle) => RuntimeBundle | Promise<RuntimeBundle>;
888
+ /** Evaluated for every authorized operation; never cached as placement authority. */
889
+ readonly resolveFilesystemBindings?: (input: {
890
+ readonly verifiedClaim: VerifiedAgentScopeClaim;
891
+ readonly requestId: string;
892
+ }) => Promise<readonly RuntimeFilesystemBinding[] | undefined>;
702
893
  }
703
- interface AgentHostHttpProjectionBaseOptions {
704
- readonly defaultAgentTypeId: string;
894
+ interface AgentHostEnvironmentLease {
895
+ readonly workspace: Workspace;
896
+ readonly gitWorkspace: Workspace;
897
+ readonly fileSearch: FileSearch;
898
+ readonly filesystemBindings?: readonly RuntimeFilesystemBinding[];
899
+ readonly readiness: Readonly<AgentCapabilityReadiness>;
900
+ readonly signal: AbortSignal;
901
+ release(): void;
902
+ }
903
+ interface AgentHostDispatcherRunInput extends WorkspaceAgentDirectRunInput {
904
+ readonly authorizedScope: AuthorizedAgentScope;
905
+ readonly request?: FastifyRequest;
906
+ }
907
+ interface AgentHostDirectProjectionOptions {
908
+ readonly authorizeAgentRequest: (request: FastifyRequest) => Promise<AuthorizedAgentScope>;
909
+ readonly filterModels?: ModelsRoutesOptions['filterModels'];
910
+ readonly sessionChangesTracker?: SessionChangesTracker;
911
+ readonly defaultSessionId?: string;
705
912
  }
706
- /** Addressed Gateway projection, optionally with its frozen Pi-chat aliases. */
707
- type AgentHostAddressedHttpProjectionOptions = AgentHostHttpProjectionBaseOptions & {
708
- readonly authorizeRequest: (request: FastifyRequest) => Promise<AuthorizedAgentScope>;
709
- readonly legacyPiChatAliases?: boolean;
710
- readonly legacyRoutePolicy?: never;
711
- };
712
- /** Full legacy/application route profile with its own normalized scope bridge. */
713
- type AgentHostLegacyHttpProjectionOptions = AgentHostHttpProjectionBaseOptions & {
714
- readonly legacyRoutePolicy: AgentHostLegacyRoutePolicy;
715
- readonly authorizeRequest?: never;
716
- readonly legacyPiChatAliases?: never;
717
- };
718
- type AgentHostHttpProjectionOptions = AgentHostAddressedHttpProjectionOptions | AgentHostLegacyHttpProjectionOptions;
719
913
  interface AgentHostDescription {
720
914
  readonly hostId: string;
721
915
  readonly agents: readonly {
722
916
  readonly agentTypeId: string;
723
917
  readonly label: string;
918
+ /** Computed definition identity digest (instructions + knowledge bytes), when the spec carries one. */
919
+ readonly definitionDigest?: string;
724
920
  }[];
725
921
  readonly draining: boolean;
726
922
  }
@@ -738,13 +934,29 @@ interface CreateAgentHostOptions {
738
934
  readonly runtimeModeAdapter: RuntimeModeAdapter;
739
935
  readonly runtimeHost?: AgentRuntimeHostOperations;
740
936
  readonly sessionRoot?: string;
741
- readonly resolveRuntimeScope: (input: {
937
+ readonly resolveAuthorizedEnvironmentScope?: (input: {
938
+ readonly authorizedScope: AuthorizedAgentScope;
939
+ readonly verifiedClaim: VerifiedAgentScopeClaim;
940
+ readonly intent: AuthorizedEnvironmentIntent;
941
+ }) => Promise<AgentHostEnvironmentScope>;
942
+ readonly resolveAuthorizedAgentRuntimeScope?: (input: {
943
+ readonly authorizedScope: AuthorizedAgentScope;
944
+ readonly verifiedClaim: VerifiedAgentScopeClaim;
742
945
  readonly agentTypeId: string;
743
- readonly scope: AuthorizedAgentScope;
744
- }) => Promise<ResolvedAgentRuntimeScope>;
946
+ readonly intent: AuthorizedEnvironmentIntent & {
947
+ readonly kind: 'agent-binding';
948
+ readonly operation: 'new-binding' | 'existing-session' | 'reload';
949
+ readonly sessionId?: string;
950
+ };
951
+ readonly environment: AgentHostEnvironmentScope;
952
+ }) => Promise<Omit<ResolvedAgentRuntimeScope, 'environment'>>;
745
953
  readonly telemetry?: TelemetrySink;
746
954
  readonly metering?: AgentMeteringSink;
747
955
  readonly requestLedger?: AgentRequestLedger;
956
+ /** Durable effect ledger path, independent of transcript/session storage. */
957
+ readonly requestLedgerPath?: string;
958
+ /** Explicit test/dev opt-in for an in-memory ledger. */
959
+ readonly inMemoryRequestLedgerMode?: 'test' | 'development';
748
960
  readonly requestRetentionMs?: number;
749
961
  readonly effectAdmission?: AgentEffectAdmission;
750
962
  readonly shutdownGraceMs?: number;
@@ -753,7 +965,12 @@ interface CreateAgentHostOptions {
753
965
  interface CreatedAgentHost {
754
966
  readonly host: AgentHostHandle;
755
967
  readonly gateway: AgentGateway;
756
- registerRoutes(options: AgentHostHttpProjectionOptions): FastifyPluginAsync;
968
+ registerDirectRoutes(options: AgentHostDirectProjectionOptions): FastifyPluginAsync;
969
+ acquireEnvironment(input: {
970
+ readonly authorizedScope: AuthorizedAgentScope;
971
+ readonly intent: AuthorizedEnvironmentIntent;
972
+ }): Promise<AgentHostEnvironmentLease>;
973
+ runWithWorkspaceAgent(input: AgentHostDispatcherRunInput, run: (binding: LeaseBoundWorkspaceAgent) => Promise<void>): Promise<void>;
757
974
  }
758
975
 
759
- export { type PiPackageSource as $, type AgentGatewayEffect as A, type BuiltinRuntimeModeId as B, type CreateAgentHostOptions as C, type AgentHostHttpProjectionOptions as D, type AgentHostLegacyHttpProjectionOptions as E, type AgentHostLegacyProjectionComposition as F, type AgentHostLegacyProjectionLifecycle as G, type AgentHostLegacyProjectionRuntime as H, type AgentHostLegacyRoutePolicyMountInput as I, type ConfiguredAgentHostAgentSpec as J, type MeteringReleaseInput as K, type LegacyDefaultAgentHostSpec as L, type ModeContext as M, type MeteringReleaseReason as N, type MeteringReservationResult as O, type ProvisionWorkspaceRuntimeOptions as P, type MeteringReserveInput as Q, type RuntimeModeAdapter as R, type MeteringRunKind as S, type MeteringRunScope as T, type MeteringRunStatus as U, type MeteringSettleInput as V, type WorkspaceProvisioningResult as W, type MeteringUsage as X, type MeteringUsageInput as Y, PI_PACKAGE_RESOURCE_FILTERS as Z, type PiExtensionFactory as _, type RuntimeModeId as a, type PluginSkillSource as a0, type ResolvedEnvironmentScope as a1, type RuntimeFilesystemBindingOperations as a2, type RuntimeNodePackageSpec as a3, type RuntimeProvisioningContribution as a4, type RuntimePythonSpec as a5, type RuntimeTemplateContribution as a6, type WorkspaceProvisioningExecResult as a7, compactPiPackages as a8, createResourceSettingsManager as a9, mergePiPackageSources as aa, normalizeMeteringUsage as ab, piPackageSourceKey as ac, type AgentRuntimeHostOperations as b, type RuntimeBashStrategy as c, type RuntimeFilesystemStrategy as d, type WorkspaceProvisioningAdapter as e, type RuntimeBundle as f, type PiHarnessOptions as g, type AgentMeteringSink as h, type RuntimeFilesystemBinding as i, type MeteringErrorLogger as j, ReadyStatusTracker as k, type ResolvedAgentRuntimeScope as l, type CompiledAgentHostAgentSpec as m, type AgentRequestLedger as n, type AgentEffectAdmission as o, type AgentRequestKey as p, type CreatedAgentHost as q, type AgentFleetCompiler as r, type AgentRequestTarget as s, type AgentRequestLedgerRecord as t, type AgentRequestFailure as u, type AgentHostLegacyRoutePolicy as v, type AgentHostAddressedHttpProjectionOptions as w, type AgentHostAgentSpec as x, type AgentHostDescription as y, type AgentHostHandle as z };
976
+ export { type PiExtensionFactory as $, type AgentGatewayEffect as A, type BuiltinRuntimeModeId as B, type ConfiguredAgentHostAgentSpec as C, type AgentFleetCompiler as D, type AgentRequestTarget as E, type RuntimeFilesystemAccessDecision as F, type AgentHostDescription as G, type AgentHostDirectProjectionOptions as H, type AgentHostDispatcherRunInput as I, type AgentHostEnvironmentLease as J, type AgentHostHandle as K, type LegacyDefaultAgentHostSpec as L, type ModeContext as M, type MeteringReleaseInput as N, type MeteringReleaseReason as O, type ProvisionWorkspaceRuntimeOptions as P, type MeteringReservationResult as Q, type RuntimeModeAdapter as R, type MeteringReserveInput as S, type MeteringRunKind as T, type MeteringRunScope as U, type MeteringRunStatus as V, type WorkspaceProvisioningResult as W, type MeteringSettleInput as X, type MeteringUsage as Y, type MeteringUsageInput as Z, PI_PACKAGE_RESOURCE_FILTERS as _, type PiPackageSource as a, type PluginSkillSource as a0, type ResolvedEnvironmentScope as a1, type RuntimeFilesystemBindingOperations as a2, type RuntimeNodePackageSpec as a3, type RuntimeProvisioningContribution as a4, type RuntimePythonSpec as a5, type RuntimeTemplateContribution as a6, type WorkspaceProvisioningExecResult as a7, compactPiPackages as a8, mergePiPackageSources as a9, normalizeMeteringUsage as aa, piPackageSourceKey as ab, type RuntimeModeId as b, type AgentRuntimeHostOperations as c, type RuntimeBashStrategy as d, type RuntimeFilesystemStrategy as e, type WorkspaceProvisioningAdapter as f, type AgentInstructionFileRef as g, type AgentHostAgentSpec as h, type RuntimeBundle as i, type PiHarnessOptions as j, type AgentMeteringSink as k, type RuntimeFilesystemBinding as l, type CreatedAgentHost as m, type MeteringErrorLogger as n, ReadyStatusTracker as o, type ResolvedAgentRuntimeScope as p, type CreateAgentHostOptions as q, type CompiledAgentHostAgentSpec as r, type AgentRequestLedger as s, type AgentEffectAdmission as t, type AuthorizedEnvironmentIntent as u, type AgentHostEnvironmentScope as v, type AgentRequestKey as w, type AgentRequestLedgerPrepareResult as x, type AgentRequestFailure as y, type AgentRequestLedgerRecord as z };
@@ -97,19 +97,22 @@ shorthand. Prompts add `displayContent?`, `model?`, `thinkingLevel?`,
97
97
 
98
98
  ## Error codes
99
99
 
100
- Thirteen, exhaustive, order-stable, exported as both a const map and
100
+ Fifteen, exhaustive, order-stable, exported as both a const map and
101
101
  `AGENT_GATEWAY_ERROR_CODES`:
102
102
 
103
103
  `AGENT_TYPE_UNKNOWN` · `AGENT_SESSION_NOT_FOUND` · `AGENT_SCOPE_DENIED` ·
104
104
  `AGENT_SESSION_REPLAY_GAP` · `AGENT_SESSION_CURSOR_AHEAD` ·
105
105
  `AGENT_SESSION_CURSOR_EXPIRED` · `AGENT_SESSION_CURSOR_INVALID` ·
106
- `AGENT_REQUEST_CONFLICT` · `AGENT_REQUEST_OUTCOME_UNKNOWN` ·
106
+ `AGENT_REQUEST_CONFLICT` · `AGENT_REQUEST_IN_PROGRESS` ·
107
+ `AGENT_REQUEST_OUTCOME_UNKNOWN` · `AGENT_RUNTIME_RESTART_REQUIRED` ·
107
108
  `AGENT_COMMAND_INVALID_STATE` · `AGENT_SESSION_RUNTIME_SCOPE_MISMATCH` ·
108
109
  `AGENT_SHARED_ENVIRONMENT_UNAVAILABLE` · `AGENT_GATEWAY_CLOSED`
109
110
 
110
111
  HTTP mapping lives in `server/agent-host/httpProjection.ts`
111
112
  (`statusForGatewayError`). Note `AGENT_SESSION_RUNTIME_SCOPE_MISMATCH`,
112
- `AGENT_REQUEST_CONFLICT` and `AGENT_COMMAND_INVALID_STATE` project to **409**.
113
+ `AGENT_REQUEST_CONFLICT`, `AGENT_REQUEST_IN_PROGRESS`,
114
+ `AGENT_RUNTIME_RESTART_REQUIRED`, and `AGENT_COMMAND_INVALID_STATE` project to
115
+ **409**.
113
116
 
114
117
  ## Conformance levels
115
118
 
@@ -0,0 +1,80 @@
1
+ # Workspace agent packages
2
+
3
+ With `BORING_AGENT_FLEET=1`, a single-workspace host may discover an agent
4
+ definition from either the trusted repository's `.agents/personas/` packages
5
+ or a local package path registered in that workspace's
6
+ `.pi/settings.json#packages`. Registration makes an agent package discoverable.
7
+ It does not activate the agent: the class-B `.agents/factory/fleet.yaml` roster
8
+ must also seat the package's `boring.agent.definitionId`.
9
+
10
+ Agent fleet changes are boot-time changes. `/reload` can refresh ordinary
11
+ plugin resources, but installing, updating, seating, unseating, or removing an
12
+ agent requires restarting the workspace/CLI host.
13
+
14
+ The CLI workspaces hub has one Agent Host shared by every registered workspace.
15
+ Its global fleet therefore admits only personas from the trusted repository's
16
+ `.agents/personas/`; it does not admit agent definitions from any workspace's
17
+ local package registrations. Local packages keep their ordinary plugin
18
+ surfaces in their owning workspace. Seating workspace-local agent definitions
19
+ in workspaces mode requires a future workspace-scoped fleet boundary.
20
+
21
+ ## Install and seat
22
+
23
+ From the workspace root, register a local package directory:
24
+
25
+ ```bash
26
+ boring-ui-plugin install --local --workspace . ../agent-packages/my-agent
27
+ ```
28
+
29
+ The package keeps all of its normal plugin surfaces. Its agent contribution is
30
+ still inert until the fleet roster names its definition id:
31
+
32
+ ```yaml
33
+ seats:
34
+ - seat: my-agent
35
+ agentTypeId: my-agent-definition
36
+ skills: []
37
+ ```
38
+
39
+ Restart a single-workspace host with `BORING_AGENT_FLEET=1`. A valid seated
40
+ package appears in the agent catalog. An installed package without a matching
41
+ seat remains inert and reports `AGENT_DEFINITION_UNSEATED` during fleet
42
+ composition. The shared CLI workspaces hub never admits the local agent
43
+ contribution, even when the global roster names its definition id.
44
+
45
+ ## Update
46
+
47
+ 1. Update the source directory and bump both package/agent versions as needed.
48
+ 2. For repository personas under `.agents/personas/`, run
49
+ `pnpm write:skill-digests` from the repository root.
50
+ 3. Restart the workspace/CLI host.
51
+
52
+ Digest refresh is intentionally repository-local in v1. The script reads only
53
+ `.agents/personas/`; it does not rewrite pins for agent packages installed from
54
+ another local directory. Such packages must already have matching
55
+ seat-authoritative skill pins. A mismatch excludes only that seat with
56
+ `AGENT_FLEET_SEAT_SKILL_DIGEST_MISMATCH`; the rest of the fleet still boots.
57
+
58
+ ## Unseat or remove
59
+
60
+ To make a package inert but keep it installed, remove its seat from
61
+ `.agents/factory/fleet.yaml` and restart.
62
+
63
+ To remove its workspace registration as well:
64
+
65
+ ```bash
66
+ boring-ui-plugin remove --local --workspace . my-agent-plugin-id
67
+ ```
68
+
69
+ Then restart. If the roster still names the removed definition, that seat is
70
+ excluded with `AGENT_FLEET_SEAT_PERSONA_INVALID` while other agents boot.
71
+
72
+ ## v1 distribution boundary
73
+
74
+ Repository personas may contribute agents to any fleet in v1. A
75
+ workspace-registered local package path may contribute an agent only to a
76
+ single-workspace host; it never enters the CLI workspaces hub's global fleet.
77
+ Git/npm package sources — including their materialized `.pi/git/` and
78
+ `.pi/npm/` directories — cannot contribute an agent until the
79
+ remote-distribution trust gate ships. All excluded packages' non-agent plugin
80
+ surfaces continue through the normal plugin pipeline unchanged.