@orkestrel/agent 0.0.42 → 0.0.44

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.
@@ -40,6 +40,7 @@ import type { ToolManagerInterface } from '@orkestrel/tool';
40
40
  import type { ToolOptions } from '@orkestrel/tool';
41
41
  import type { ToolResult } from '@orkestrel/tool';
42
42
  import { UnionShape } from '@orkestrel/contract';
43
+ import type { WorkspaceInterface } from '@orkestrel/workspace';
43
44
  import type { WorkspaceManagerInterface } from '@orkestrel/workspace';
44
45
 
45
46
  /**
@@ -155,6 +156,25 @@ approved: BooleanShape;
155
156
  */
156
157
  export declare type AgentBuiltin = 'load' | 'unload' | 'memo' | 'remember' | 'switch';
157
158
 
159
+ /**
160
+ * Carries what an agent run hands each tool call as `ToolContext.caller`: the workspace the run acts
161
+ * on and the paths it reaches there.
162
+ *
163
+ * @remarks
164
+ * The agent builds one for each call as the call starts, from the view of the request the model
165
+ * answered and the ceiling at that moment, the context scope intersected with the run scope. Both
166
+ * keys are always present, so a run that shows no workspace or states no `files` list says so with
167
+ * `undefined` rather than an omitted member. `ToolContext.caller` is unverified by contract and can
168
+ * reach a handler from a wire, so read it through {@link isAgentCaller} and accept its `workspace`
169
+ * only as the very instance your own registry holds under that id.
170
+ */
171
+ export declare interface AgentCaller {
172
+ /** Holds the workspace the run acts on: the one the turn's request rendered, while the ceiling admits it at the call. */
173
+ readonly workspace: WorkspaceInterface | undefined;
174
+ /** Lists the paths the run reaches in that workspace: the live ceiling's `files` list at the call (`undefined` ⇒ every path, `[]` ⇒ none). */
175
+ readonly files: readonly string[] | undefined;
176
+ }
177
+
158
178
  /**
159
179
  * Represents a streamed step of an agent turn — the union the loop yields as it runs, discriminated
160
180
  * by the `category` of step it carries, and the pull surface beside the push {@link AgentEventMap}.
@@ -988,7 +1008,7 @@ category: LiteralShape<readonly ["error"]>;
988
1008
  * judge, a tool handler, and a selection handler are awaited until they settle, because each can
989
1009
  * carry usage or finished work, so one that ignores its signal holds the run past a cancel or a
990
1010
  * timeout, and on a ledger its held scan, until it returns.
991
- * The agent supplies no caller identity.
1011
+ * Each call's `ToolContext.caller` is an {@link AgentCaller}.
992
1012
  * - **Paced + capped.** The `scheduler` (when given) yields between turns; tool
993
1013
  * iteration is capped at `limit` so the loop always terminates.
994
1014
  * - **Two observation surfaces.** Pull: the {@link AgentChunk} stream (`stream().events`)
@@ -7259,6 +7279,29 @@ export declare const INVALID_RELAY_STATUS = 400;
7259
7279
  */
7260
7280
  export declare function isAgentBuiltin(value: unknown): value is AgentBuiltin;
7261
7281
 
7282
+ /**
7283
+ * Checks whether a value is an agent caller: a plain record whose own keys are exactly `workspace`
7284
+ * and `files`, whose `workspace` is `undefined` or an object, and whose `files` is `undefined` or an
7285
+ * array of strings.
7286
+ *
7287
+ * @remarks
7288
+ * Total: each member is read once, and an omitted, inherited, or undeclared member, a throwing
7289
+ * accessor, and a revoked `Proxy` return false rather than throw. It checks the shape a caller
7290
+ * carries, never that `workspace` is a live workspace: a value that crossed a wire passes when it
7291
+ * holds that shape, so accept its `workspace` only as the very instance your own registry holds
7292
+ * under that id.
7293
+ *
7294
+ * @param value - The unknown caller candidate, such as `ToolContext.caller`
7295
+ * @returns True if the value satisfies the caller contract; false otherwise
7296
+ *
7297
+ * @example
7298
+ * ```ts
7299
+ * isAgentCaller({ workspace: undefined, files: undefined }) // true
7300
+ * isAgentCaller({ workspace: 'returns' }) // false
7301
+ * ```
7302
+ */
7303
+ export declare function isAgentCaller(value: unknown): value is AgentCaller;
7304
+
7262
7305
  /**
7263
7306
  * Narrows an unknown caught value to an {@link AgentError} through its identity brand and declared members, so a `catch`
7264
7307
  * can branch on its `code`.
@@ -13105,6 +13148,30 @@ export declare function resolveDisclosure(context: AgentContextInterface, conver
13105
13148
  */
13106
13149
  export declare function resolvePredict(predict: number | undefined, capacity: number): number;
13107
13150
 
13151
+ /**
13152
+ * Resolves the workspace a run renders and acts on: the one `selected` names, else the registry's
13153
+ * active one, kept only while `allowed` admits its id.
13154
+ *
13155
+ * @remarks
13156
+ * A selection the registry does not hold resolves to `undefined` and never falls back to the active
13157
+ * workspace. `allowed` is three-way, as {@link import('../helpers.js').filterAllowList} reads it.
13158
+ * `AgentContext.build`, the caller an agent run hands each tool call, and a ledger's calibration
13159
+ * resolve through it, so what a request renders and what a call receives come from one rule.
13160
+ *
13161
+ * @param workspaces - The workspace registry to read
13162
+ * @param selected - The id a `switch` call or the `workspace` option selected, or `undefined`
13163
+ * @param allowed - The ceiling's `workspaces` list (`undefined` ⇒ every id, `[]` ⇒ none)
13164
+ * @returns The workspace, or `undefined` when none resolves
13165
+ *
13166
+ * @example
13167
+ * ```ts
13168
+ * import { resolveWorkspace } from '@orkestrel/agent'
13169
+ *
13170
+ * resolveWorkspace(agent.context.workspaces, 'returns', ['returns']) // the registered returns workspace
13171
+ * ```
13172
+ */
13173
+ export declare function resolveWorkspace(workspaces: WorkspaceManagerInterface, selected: string | undefined, allowed: readonly string[] | undefined): WorkspaceInterface | undefined;
13174
+
13108
13175
  /** Lists the members `AgentRunnerOptions` declares, frozen — the keys `createAgentRunner` admits. */
13109
13176
  export declare const RUNNER_OPTION_KEYS: readonly ["registry", "partial", "concurrency", "retries", "timeout"];
13110
13177
 
@@ -13320,7 +13387,9 @@ export declare const SCOPE_NOTE = "it is not one of the listed tools. Use a list
13320
13387
  * message and the image files attached to the last user message — and `workspaces` decides
13321
13388
  * whether that workspace renders at all. Two lists bound a write as well as a read: the
13322
13389
  * `remember` built-in writes only a name a defined `memos` list holds, and the `switch` built-in
13323
- * selects only an id a defined `workspaces` list holds.
13390
+ * selects only an id a defined `workspaces` list holds. The `files` list also bounds the workspace
13391
+ * tool of `@orkestrel/toolbox`, which receives it as `caller.files`, an
13392
+ * {@link import('../agents/types.js').AgentCaller} member.
13324
13393
  */
13325
13394
  export declare interface ScopeFilter {
13326
13395
  /** Lists the allowed instruction names matched against the `name` property (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). */
@@ -13343,7 +13412,8 @@ export declare interface ScopeFilter {
13343
13412
  * Lists the allowed active-workspace file paths matched against the `path` property (`undefined` ⇒ all, `[]` ⇒ none, else only-listed) —
13344
13413
  * the filter {@link AgentContextInterface.build} applies to the rendered workspace's
13345
13414
  * {@link import('@orkestrel/workspace').WorkspaceInterface.files} before rendering them (text → the context message, image →
13346
- * the last user message).
13415
+ * the last user message). Each tool call receives the list as `caller.files`, and the workspace
13416
+ * tool of `@orkestrel/toolbox` reaches the listed paths alone.
13347
13417
  */
13348
13418
  readonly files?: readonly string[];
13349
13419
  /**
@@ -40,6 +40,7 @@ import type { ToolManagerInterface } from '@orkestrel/tool';
40
40
  import type { ToolOptions } from '@orkestrel/tool';
41
41
  import type { ToolResult } from '@orkestrel/tool';
42
42
  import { UnionShape } from '@orkestrel/contract';
43
+ import type { WorkspaceInterface } from '@orkestrel/workspace';
43
44
  import type { WorkspaceManagerInterface } from '@orkestrel/workspace';
44
45
 
45
46
  /**
@@ -155,6 +156,25 @@ approved: BooleanShape;
155
156
  */
156
157
  export declare type AgentBuiltin = 'load' | 'unload' | 'memo' | 'remember' | 'switch';
157
158
 
159
+ /**
160
+ * Carries what an agent run hands each tool call as `ToolContext.caller`: the workspace the run acts
161
+ * on and the paths it reaches there.
162
+ *
163
+ * @remarks
164
+ * The agent builds one for each call as the call starts, from the view of the request the model
165
+ * answered and the ceiling at that moment, the context scope intersected with the run scope. Both
166
+ * keys are always present, so a run that shows no workspace or states no `files` list says so with
167
+ * `undefined` rather than an omitted member. `ToolContext.caller` is unverified by contract and can
168
+ * reach a handler from a wire, so read it through {@link isAgentCaller} and accept its `workspace`
169
+ * only as the very instance your own registry holds under that id.
170
+ */
171
+ export declare interface AgentCaller {
172
+ /** Holds the workspace the run acts on: the one the turn's request rendered, while the ceiling admits it at the call. */
173
+ readonly workspace: WorkspaceInterface | undefined;
174
+ /** Lists the paths the run reaches in that workspace: the live ceiling's `files` list at the call (`undefined` ⇒ every path, `[]` ⇒ none). */
175
+ readonly files: readonly string[] | undefined;
176
+ }
177
+
158
178
  /**
159
179
  * Represents a streamed step of an agent turn — the union the loop yields as it runs, discriminated
160
180
  * by the `category` of step it carries, and the pull surface beside the push {@link AgentEventMap}.
@@ -988,7 +1008,7 @@ category: LiteralShape<readonly ["error"]>;
988
1008
  * judge, a tool handler, and a selection handler are awaited until they settle, because each can
989
1009
  * carry usage or finished work, so one that ignores its signal holds the run past a cancel or a
990
1010
  * timeout, and on a ledger its held scan, until it returns.
991
- * The agent supplies no caller identity.
1011
+ * Each call's `ToolContext.caller` is an {@link AgentCaller}.
992
1012
  * - **Paced + capped.** The `scheduler` (when given) yields between turns; tool
993
1013
  * iteration is capped at `limit` so the loop always terminates.
994
1014
  * - **Two observation surfaces.** Pull: the {@link AgentChunk} stream (`stream().events`)
@@ -7259,6 +7279,29 @@ export declare const INVALID_RELAY_STATUS = 400;
7259
7279
  */
7260
7280
  export declare function isAgentBuiltin(value: unknown): value is AgentBuiltin;
7261
7281
 
7282
+ /**
7283
+ * Checks whether a value is an agent caller: a plain record whose own keys are exactly `workspace`
7284
+ * and `files`, whose `workspace` is `undefined` or an object, and whose `files` is `undefined` or an
7285
+ * array of strings.
7286
+ *
7287
+ * @remarks
7288
+ * Total: each member is read once, and an omitted, inherited, or undeclared member, a throwing
7289
+ * accessor, and a revoked `Proxy` return false rather than throw. It checks the shape a caller
7290
+ * carries, never that `workspace` is a live workspace: a value that crossed a wire passes when it
7291
+ * holds that shape, so accept its `workspace` only as the very instance your own registry holds
7292
+ * under that id.
7293
+ *
7294
+ * @param value - The unknown caller candidate, such as `ToolContext.caller`
7295
+ * @returns True if the value satisfies the caller contract; false otherwise
7296
+ *
7297
+ * @example
7298
+ * ```ts
7299
+ * isAgentCaller({ workspace: undefined, files: undefined }) // true
7300
+ * isAgentCaller({ workspace: 'returns' }) // false
7301
+ * ```
7302
+ */
7303
+ export declare function isAgentCaller(value: unknown): value is AgentCaller;
7304
+
7262
7305
  /**
7263
7306
  * Narrows an unknown caught value to an {@link AgentError} through its identity brand and declared members, so a `catch`
7264
7307
  * can branch on its `code`.
@@ -13105,6 +13148,30 @@ export declare function resolveDisclosure(context: AgentContextInterface, conver
13105
13148
  */
13106
13149
  export declare function resolvePredict(predict: number | undefined, capacity: number): number;
13107
13150
 
13151
+ /**
13152
+ * Resolves the workspace a run renders and acts on: the one `selected` names, else the registry's
13153
+ * active one, kept only while `allowed` admits its id.
13154
+ *
13155
+ * @remarks
13156
+ * A selection the registry does not hold resolves to `undefined` and never falls back to the active
13157
+ * workspace. `allowed` is three-way, as {@link import('../helpers.js').filterAllowList} reads it.
13158
+ * `AgentContext.build`, the caller an agent run hands each tool call, and a ledger's calibration
13159
+ * resolve through it, so what a request renders and what a call receives come from one rule.
13160
+ *
13161
+ * @param workspaces - The workspace registry to read
13162
+ * @param selected - The id a `switch` call or the `workspace` option selected, or `undefined`
13163
+ * @param allowed - The ceiling's `workspaces` list (`undefined` ⇒ every id, `[]` ⇒ none)
13164
+ * @returns The workspace, or `undefined` when none resolves
13165
+ *
13166
+ * @example
13167
+ * ```ts
13168
+ * import { resolveWorkspace } from '@orkestrel/agent'
13169
+ *
13170
+ * resolveWorkspace(agent.context.workspaces, 'returns', ['returns']) // the registered returns workspace
13171
+ * ```
13172
+ */
13173
+ export declare function resolveWorkspace(workspaces: WorkspaceManagerInterface, selected: string | undefined, allowed: readonly string[] | undefined): WorkspaceInterface | undefined;
13174
+
13108
13175
  /** Lists the members `AgentRunnerOptions` declares, frozen — the keys `createAgentRunner` admits. */
13109
13176
  export declare const RUNNER_OPTION_KEYS: readonly ["registry", "partial", "concurrency", "retries", "timeout"];
13110
13177
 
@@ -13320,7 +13387,9 @@ export declare const SCOPE_NOTE = "it is not one of the listed tools. Use a list
13320
13387
  * message and the image files attached to the last user message — and `workspaces` decides
13321
13388
  * whether that workspace renders at all. Two lists bound a write as well as a read: the
13322
13389
  * `remember` built-in writes only a name a defined `memos` list holds, and the `switch` built-in
13323
- * selects only an id a defined `workspaces` list holds.
13390
+ * selects only an id a defined `workspaces` list holds. The `files` list also bounds the workspace
13391
+ * tool of `@orkestrel/toolbox`, which receives it as `caller.files`, an
13392
+ * {@link import('../agents/types.js').AgentCaller} member.
13324
13393
  */
13325
13394
  export declare interface ScopeFilter {
13326
13395
  /** Lists the allowed instruction names matched against the `name` property (`undefined` ⇒ all, `[]` ⇒ none, else only-listed). */
@@ -13343,7 +13412,8 @@ export declare interface ScopeFilter {
13343
13412
  * Lists the allowed active-workspace file paths matched against the `path` property (`undefined` ⇒ all, `[]` ⇒ none, else only-listed) —
13344
13413
  * the filter {@link AgentContextInterface.build} applies to the rendered workspace's
13345
13414
  * {@link import('@orkestrel/workspace').WorkspaceInterface.files} before rendering them (text → the context message, image →
13346
- * the last user message).
13415
+ * the last user message). Each tool call receives the list as `caller.files`, and the workspace
13416
+ * tool of `@orkestrel/toolbox` reaches the listed paths alone.
13347
13417
  */
13348
13418
  readonly files?: readonly string[];
13349
13419
  /**
@@ -1,4 +1,4 @@
1
- import { ContractError, INTRINSICS, admitValue, arrayOf, arrayShape, attempt, booleanShape, boundsOf, canonicalStringify, cloneJSONValue, createContract, describeFaults, errorToMessage, failure, holds, integerShape, isArray, isBoolean, isError, isFiniteNumber, isFunction, isJSONValue, isNumber, isObject, isPromiseLike, isRecord, isString, jsonShape, literalOf, literalShape, nullableOf, nullableShape, numberShape, objectOf, objectShape, optionalOf, optionalShape, parseJSON, parseJSONAs, parseJSONValue, preview, rawShape, recordOf, recordShape, refuseOptionKeys, schemaToParameters, schemaToShape, stringShape, success, unionOf, unionShape } from "@orkestrel/contract";
1
+ import { ContractError, INTRINSICS, admitValue, arrayOf, arrayShape, attempt, booleanShape, boundsOf, canonicalStringify, cloneJSONValue, createContract, describeFaults, errorToMessage, failure, holds, integerShape, isArray, isBoolean, isError, isFiniteNumber, isFunction, isJSONValue, isNumber, isObject, isPromiseLike, isRecord, isString, jsonShape, literalOf, literalShape, matchesExactKeys, nullableOf, nullableShape, numberShape, objectOf, objectShape, optionalOf, optionalShape, parseJSON, parseJSONAs, parseJSONValue, preview, rawShape, recordOf, recordShape, refuseOptionKeys, schemaToParameters, schemaToShape, stringShape, success, unionOf, unionShape } from "@orkestrel/contract";
2
2
  import { createTokenBudget, createTokenMeter, isBudget, isBudgetAmount, isBudgetError, isTokenUsage } from "@orkestrel/budget";
3
3
  import { ToolError, ToolManager, createTool, createToolManager, isToolCall, isToolError } from "@orkestrel/tool";
4
4
  import { createNDJSONParser } from "@orkestrel/ndjson";
@@ -5227,6 +5227,32 @@ function intersectFilters(parent, child) {
5227
5227
  };
5228
5228
  }
5229
5229
  /**
5230
+ * Resolves the workspace a run renders and acts on: the one `selected` names, else the registry's
5231
+ * active one, kept only while `allowed` admits its id.
5232
+ *
5233
+ * @remarks
5234
+ * A selection the registry does not hold resolves to `undefined` and never falls back to the active
5235
+ * workspace. `allowed` is three-way, as {@link import('../helpers.js').filterAllowList} reads it.
5236
+ * `AgentContext.build`, the caller an agent run hands each tool call, and a ledger's calibration
5237
+ * resolve through it, so what a request renders and what a call receives come from one rule.
5238
+ *
5239
+ * @param workspaces - The workspace registry to read
5240
+ * @param selected - The id a `switch` call or the `workspace` option selected, or `undefined`
5241
+ * @param allowed - The ceiling's `workspaces` list (`undefined` ⇒ every id, `[]` ⇒ none)
5242
+ * @returns The workspace, or `undefined` when none resolves
5243
+ *
5244
+ * @example
5245
+ * ```ts
5246
+ * import { resolveWorkspace } from '@orkestrel/agent'
5247
+ *
5248
+ * resolveWorkspace(agent.context.workspaces, 'returns', ['returns']) // the registered returns workspace
5249
+ * ```
5250
+ */
5251
+ function resolveWorkspace(workspaces, selected, allowed) {
5252
+ const workspace = selected === void 0 ? workspaces.active : workspaces.workspace(selected);
5253
+ return workspace !== void 0 && filterAllowList(allowed, [workspace.id], (id) => id).length > 0 ? workspace : void 0;
5254
+ }
5255
+ /**
5230
5256
  * Renders one index line for a memo or a skill — `- name: description`, the built-in `render` of
5231
5257
  * the memo and skill managers.
5232
5258
  *
@@ -6282,10 +6308,8 @@ var AgentContext = class {
6282
6308
  return skill === void 0 || skill.content.trim() === "" ? [] : [skill];
6283
6309
  }), renderSkillBody, void 0);
6284
6310
  if (bodies !== void 0) parts.push(bodies);
6285
- const selected = options?.disclosure?.workspace;
6286
- const workspace = selected === void 0 ? this.#workspaces.active : this.#workspaces.workspace(selected);
6287
- const shown = filterAllowList(scope.workspaces, workspace === void 0 ? [] : [workspace], (one) => one.id);
6288
- const files = filterAllowList(scope.files, shown.flatMap((one) => one.files()), (one) => one.path);
6311
+ const workspace = resolveWorkspace(this.#workspaces, options?.disclosure?.workspace, scope.workspaces);
6312
+ const files = filterAllowList(scope.files, workspace?.files() ?? [], (one) => one.path);
6289
6313
  const documented = renderSection(WORKSPACE_SECTION_HEADER, files.flatMap((file) => isTextContent(file.content) ? [{
6290
6314
  path: file.path,
6291
6315
  language: file.content.language,
@@ -7252,6 +7276,35 @@ function isAuthorityDecision(value) {
7252
7276
  reason: isString
7253
7277
  }, ["reason"])(value);
7254
7278
  }
7279
+ /**
7280
+ * Checks whether a value is an agent caller: a plain record whose own keys are exactly `workspace`
7281
+ * and `files`, whose `workspace` is `undefined` or an object, and whose `files` is `undefined` or an
7282
+ * array of strings.
7283
+ *
7284
+ * @remarks
7285
+ * Total: each member is read once, and an omitted, inherited, or undeclared member, a throwing
7286
+ * accessor, and a revoked `Proxy` return false rather than throw. It checks the shape a caller
7287
+ * carries, never that `workspace` is a live workspace: a value that crossed a wire passes when it
7288
+ * holds that shape, so accept its `workspace` only as the very instance your own registry holds
7289
+ * under that id.
7290
+ *
7291
+ * @param value - The unknown caller candidate, such as `ToolContext.caller`
7292
+ * @returns True if the value satisfies the caller contract; false otherwise
7293
+ *
7294
+ * @example
7295
+ * ```ts
7296
+ * isAgentCaller({ workspace: undefined, files: undefined }) // true
7297
+ * isAgentCaller({ workspace: 'returns' }) // false
7298
+ * ```
7299
+ */
7300
+ function isAgentCaller(value) {
7301
+ return holds(() => {
7302
+ if (!isRecord(value) || !matchesExactKeys(value, ["workspace", "files"])) return false;
7303
+ const workspace = value.workspace;
7304
+ const files = value.files;
7305
+ return (workspace === void 0 || isObject(workspace)) && (files === void 0 || arrayOf(isString)(files));
7306
+ });
7307
+ }
7255
7308
  // src/core/agents/helpers.ts
7256
7309
  /**
7257
7310
  * Projects an unknown value onto a fresh, exact `JSONValue` representation of an
@@ -8616,6 +8669,7 @@ function collectDisclosure(conversation, builtins) {
8616
8669
  * registers under a built-in's name is never read: `tool` and `execute` answer a built-in's name
8617
8670
  * from the run's manager and every other name from the host's. Each handler reads the ceiling when
8618
8671
  * it runs, the context scope intersected with the run scope at that moment, never a turn's copy.
8672
+ * The `caller` each call receives reads the ceiling the same way, as the call starts.
8619
8673
  */
8620
8674
  var AgentRun = class {
8621
8675
  #context;
@@ -8628,6 +8682,7 @@ var AgentRun = class {
8628
8682
  #ceiling = {};
8629
8683
  #shown = { skills: [] };
8630
8684
  #ids = [];
8685
+ #files = [];
8631
8686
  #advertised = [];
8632
8687
  #snapshot;
8633
8688
  #selection;
@@ -8711,6 +8766,31 @@ var AgentRun = class {
8711
8766
  return this.#advertised.some((definition) => definition.name === "switch");
8712
8767
  }
8713
8768
  /**
8769
+ * Returns what a tool call receives as `ToolContext.caller`: the workspace instance the working
8770
+ * head rendered, kept only while the ceiling at this moment admits its id, and that ceiling's
8771
+ * `files` list.
8772
+ *
8773
+ * @remarks
8774
+ * The instance is the one the head's build resolved, never the registry's `active` pointer at the
8775
+ * call, so a host's `switch` made while the provider answers reaches the next turn's head and not
8776
+ * this call. Each read of this getter reads the `workspaces` and `files` lists of the context
8777
+ * scope and the run scope one time each, and no other list, so a call reads them as it starts, a
8778
+ * narrowing made after the turn's decision reaches that call, and a turn still reads its `tools`
8779
+ * list once.
8780
+ *
8781
+ * @returns A fresh caller
8782
+ */
8783
+ get caller() {
8784
+ const outer = this.#context.scope;
8785
+ const inner = this.#scope;
8786
+ const rendered = this.#head?.rendered;
8787
+ const [workspace] = filterAllowList(intersectKeys(outer?.workspaces, inner?.workspaces), rendered === void 0 ? [] : [rendered], (one) => one.id);
8788
+ return {
8789
+ workspace,
8790
+ files: intersectKeys(outer?.files, inner?.files)
8791
+ };
8792
+ }
8793
+ /**
8714
8794
  * Returns the selection the working head rendered.
8715
8795
  *
8716
8796
  * @returns The selection, or undefined before the first build
@@ -8734,8 +8814,10 @@ var AgentRun = class {
8734
8814
  * `load`, `unload`, or `switch` is enabled, and only the records of an enabled built-in count.
8735
8815
  * Registered skills hold their tools back only while `load` is enabled. The view compared with
8736
8816
  * the working head's is the ceiling's `instructions`, `skills`, `memos`, `files`, and
8737
- * `workspaces` lists, the shown skills by id, the shown workspace, and whether `switch` is
8738
- * advertised.
8817
+ * `workspaces` lists, the shown skills by id, the shown workspace, the files that workspace
8818
+ * renders under the ceiling's `files` list, compared by identity, and whether `switch` is
8819
+ * advertised. An edit to a rendered file, by a tool or by the host, therefore makes the head
8820
+ * stale, and an edit to a file no build renders does not.
8739
8821
  *
8740
8822
  * @returns True if the working head was built with another view and must be rebuilt; false otherwise
8741
8823
  */
@@ -8750,13 +8832,19 @@ var AgentRun = class {
8750
8832
  this.#ceiling = ceiling;
8751
8833
  this.#shown = shown;
8752
8834
  this.#ids = shown.skills.flatMap((name) => this.#context.skills.skill(name)?.id ?? []);
8835
+ this.#files = filterAllowList(ceiling.files, resolveWorkspace(this.#context.workspaces, shown.workspace, ceiling.workspaces)?.files() ?? [], (file) => file.path);
8753
8836
  this.#advertised = filterAdvertisedTools(this.#candidates(ceiling), ceiling.tools, this.#builtins.has("load") ? this.#context.skills.skills() : [], shown.skills);
8754
8837
  const head = this.#head;
8755
- return head === void 0 || !matchesHeadLists(head.ceiling, ceiling) || head.ids.length !== this.#ids.length || head.ids.some((id, index) => id !== this.#ids[index]) || head.workspace !== shown.workspace || head.switchable !== this.switchable;
8838
+ return head === void 0 || !matchesHeadLists(head.ceiling, ceiling) || head.ids.length !== this.#ids.length || head.ids.some((id, index) => id !== this.#ids[index]) || head.workspace !== shown.workspace || head.switchable !== this.switchable || head.files.length !== this.#files.length || head.files.some((file, index) => file !== this.#files[index]);
8756
8839
  }
8757
8840
  /**
8758
- * Records what the working head was built with: the selection, the built array's length, and
8759
- * the view the last `observe` resolved.
8841
+ * Records what the working head was built with: the selection, the built array's length, the
8842
+ * view the last `observe` resolved, and the workspace instance the build rendered.
8843
+ *
8844
+ * @remarks
8845
+ * Call it right after the build: it resolves the rendered workspace from the inputs the build
8846
+ * read, the shown workspace and the context scope's `workspaces` list intersected with the
8847
+ * snapshot's.
8760
8848
  *
8761
8849
  * @param selection - The selection the build rendered
8762
8850
  * @param length - The length of the built array
@@ -8768,7 +8856,9 @@ var AgentRun = class {
8768
8856
  ceiling: this.#ceiling,
8769
8857
  ids: this.#ids,
8770
8858
  workspace: this.#shown.workspace,
8771
- switchable: this.switchable
8859
+ switchable: this.switchable,
8860
+ files: this.#files,
8861
+ rendered: resolveWorkspace(this.#context.workspaces, this.#shown.workspace, intersectKeys(this.#context.scope?.workspaces, this.#snapshot?.workspaces))
8772
8862
  };
8773
8863
  }
8774
8864
  /**
@@ -9673,7 +9763,10 @@ var Agent = class {
9673
9763
  const { allowed, denials } = authorization;
9674
9764
  const entries = [...allowed].sort(([left], [right]) => left - right);
9675
9765
  const started = entries.map(([, { call, tool }]) => {
9676
- if (!this.#changed(run, call, tool, advertised)) return run.execute(call, { signal });
9766
+ if (!this.#changed(run, call, tool, advertised)) return run.execute(call, {
9767
+ signal,
9768
+ caller: run.caller
9769
+ });
9677
9770
  this.#emitter.emit("deny", call, `${call.name} changed after its decision`, void 0);
9678
9771
  return denyCall(call, AUTHORITY_NOTES.denied);
9679
9772
  });
@@ -13674,8 +13767,7 @@ var Ledger = class {
13674
13767
  async #measureScale(head, bare, signal) {
13675
13768
  const rate = bare / estimateMessages(head);
13676
13769
  const workspace = this.#show(intersectFilters(this.#agent.context.scope, void 0)).workspace;
13677
- const workspaces = this.#agent.context.workspaces;
13678
- const files = ((workspace === void 0 ? workspaces.active : workspaces.workspace(workspace))?.files() ?? []).flatMap((file) => isTextContent(file.content) ? [file.path] : []);
13770
+ const files = (resolveWorkspace(this.#agent.context.workspaces, workspace, void 0)?.files() ?? []).flatMap((file) => isTextContent(file.content) ? [file.path] : []);
13679
13771
  const shown = this.#agent.context.build({
13680
13772
  selection: {
13681
13773
  messages: [],
@@ -14721,6 +14813,6 @@ var Ledger = class {
14721
14813
  function createLedger(provider, options) {
14722
14814
  return new Ledger(provider, options);
14723
14815
  }
14724
- export { AGENT_OPTION_KEYS, AGENT_RUN_KEYS, ARGUMENT_BLANK_PATTERN, ARGUMENT_CONTROL_PATTERN, AUTHORITY_NOTES, AUTHORITY_OPTION_KEYS, Agent, AgentContext, AgentError, AgentFanout, AgentJobError, AgentJudge, AgentProvider, AgentRegistry, Approver, Authority, BUILD_OPTION_KEYS, BUILTIN_LIMITS, BUILTIN_NOTES, BUILTIN_TOOLS, CLASSIFIER_OPTION_KEYS, COMPACT_OPTION_KEYS, CONTEXT_OPTION_KEYS, CONVERSATION_INPUT_KEYS, CONVERSATION_MANAGER_KEYS, CONVERSATION_OPTION_KEYS, CONVERSATION_RECAP_PREFIX, CONVERSATION_ROLES, Channel, Classifier, ContextError, Conversation, ConversationError, ConversationManager, DECISIVE_CATEGORIES, DEFAULT_AGENT_LIMIT, DEFAULT_CONVERSATION_KEEP, DEFAULT_LEDGER_LIMIT, DEFAULT_LEDGER_SHARE, DEFAULT_PROVIDER_TIMEOUT, DEFAULT_RECALL_LIMIT, DEFAULT_RELAY_LIMIT, DETERMINISTIC_JUDGE_ERROR, DatabaseConversationStore, DatabaseMemoStore, GAUGE_OPTION_KEYS, Gauge, IMAGE_TOKEN_ESTIMATE, INSTRUCTION_MANAGER_KEYS, INVALID_RELAY_STATUS, Instruction, InstructionManager, JOB_REFUSAL_PREFIX, JUDGE_INPUT_KEYS, JudgeAbortError, JudgeError, JudgmentManager, LEDGER_AGENT_KEYS, LEDGER_CATEGORIES, LEDGER_NOTES, LEDGER_OPTION_KEYS, LEDGER_OWNER_PREFIX, LEDGER_QUESTIONS, LEDGER_RECALL_LABELS, LEDGER_RULES_KEY, LEDGER_SAMPLE_BYTES, LEDGER_SCALE_DRIFT, LEDGER_SLICE, LEDGER_WORD, LOADED_SECTION_HEADER, Ledger, LedgerError, LedgerRequest, MAX_ERROR_BODY_LENGTH, MEMO_MANAGER_KEYS, MEMO_SECTION_HEADER, MESSAGE_ROLES, MESSAGE_TOKEN_OVERHEAD, MemoManager, MemoryConversationStore, MemoryMemoStore, OVERSIZED_RELAY_STATUS, PLACED_CATEGORIES, PROVIDER_INPUT_KEYS, ProviderAbortError, ProviderError, QUEUE_OPTION_KEYS, QUIET_CATEGORIES, REFERENCE_OPTION_KEYS, REFUSED_RELAY_CONTENT_TYPE, REFUSED_RELAY_STATUS, REGISTRY_OPTION_KEYS, RELAY_CONTENT_TYPE, RELAY_OPTION_KEYS, RELAY_PROVIDER_KEYS, RELAY_PROVIDER_MESSAGE, RELAY_STREAM_KEYS, RUNNER_OPTION_KEYS, RelayProvider, RelayStream, SCOPE_FILTER_KEYS, SCOPE_KEYS, SCOPE_MANAGER_KEYS, SCOPE_NOTE, SKILL_MANAGER_KEYS, SKILL_SECTION_HEADER, STREAM_OPTION_KEYS, SYSTEM_ONE_OPTION_KEYS, SYSTEM_ONE_PATH, Scope, ScopeManager, SkillManager, SystemOneJudge, THINK_CLOSE, THINK_OPEN, ThinkSplitter, UNAUTHORIZED_RELAY_STATUS, UPSTREAM_RELAY_STATUS, WORKSPACE_INDEX_HEADER, WORKSPACE_SECTION_HEADER, agentAnswerContract, agentAnswerShape, agentChunkToFrame, agentFrameContract, agentFrameShape, agentJobContract, agentJobShape, agentPromptContract, agentPromptShape, agentResultToFrame, agentResultToJSON, agentStreamToFrames, armReaderAbort, assembleResult, attachImages, attachUserImages, buildJudgeResult, buildJudgments, buildLedgerCut, buildLedgerIndex, buildLedgerLineKey, buildLedgerRenderContext, buildLines, buildProviderHeaders, buildProviderResult, buildRecallMessage, buildRecapMessage, buildRecords, buildRelayRequest, buildRequestMessage, buildSummaryMessage, builtinToolContracts, chargeUsage, collectAmendments, collectBuiltinDefinitions, collectDisclosure, collectExchanges, collectImageData, collectJobRefusals, collectLedgerEvidence, collectLedgerLines, collectLedgerReplies, collectLive, collectNames, collectProjectionIds, collectRecallMessages, collectRegistry, collectRetiredFindings, collectToolGroups, collectWriteSupersessions, computeLedgerChecksum, computeSkillPrice, computeThinking, computeToolDensity, computeToolPrice, conversationSnapshotContract, conversationSnapshotShape, copyJSON, createAgent, createAgentContext, createAgentQueue, createAgentRegistry, createAgentRunner, createApprover, createAuthority, createBuiltinTool, createChannel, createConversation, createConversationManager, createDatabaseConversationStore, createDatabaseMemoStore, createInstruction, createInstructionManager, createLedger, createMemoManager, createMemoryConversationStore, createMemoryMemoStore, createRelay, createRelayProvider, createScope, createScopeManager, createSkillManager, createSystemOneJudge, createThinkSplitter, cutListing, cutWorkspaceSample, denyCall, describeCandidates, describeQuestionRefusal, describeRelayRefusal, describeSnapshotRefusal, digestLedgerTools, digestLedgerWindow, estimateMessages, estimateRequest, estimateTokens, extractLiterals, extractQueueOptions, extractSystemOneAnswer, extractSystemOneUsage, extractWords, filterAdvertisedTools, filterAllowList, filterBuiltinCandidates, findLedgerCut, findToolCall, fitSlope, freezeJSON, handleAgentQueueJob, hasCalls, hasHiddenRecall, identifyLookup, inferStop, instructionInputContract, instructionInputShape, intersectFilters, intersectKeys, isAgentBuiltin, isAgentError, isAgentJobError, isAuthorityDecision, isAuthorityVerdict, isContextError, isConversation, isConversationError, isConversationSnapshot, isFraction, isJudgeAbortError, isJudgeAnswer, isJudgeEntry, isJudgeError, isJudgeQuestion, isJudgment, isLedgerError, isLedgerQuestion, isLedgerSnapshot, isLedgerWindowSnapshot, isMemo, isMemoOrigin, isMemoSnapshot, isMessage, isMessageInput, isNonNegativeSafeInteger, isPositiveSafeInteger, isProviderAbortError, isProviderError, isProviderResult, isScope, isSection, isSystemOneAnswer, isSystemOneResponse, joinThinking, judgeAnswerContract, judgeAnswerShape, judgeEntryShape, judgeQuestionContract, judgeQuestionShape, judgmentContract, judgmentShape, ledgerSnapshotContract, ledgerSnapshotShape, ledgerWindowContract, ledgerWindowShape, linkOwners, loadToolContract, loadToolShape, matchEntities, matchesCutLine, matchesHeadLists, matchesJSON, matchesJudgment, matchesLookup, matchesPlainLine, measureAnswer, measureMessage, measureRequest, memoContract, memoInputContract, memoInputShape, memoShape, memoSnapshotContract, memoSnapshotShape, memoToolContract, memoToolShape, mergeSupersessions, messageContract, messageInputContract, messageInputShape, messageShape, normalizeArgument, normalizeWord, placeMember, providerRequestContract, providerRequestShape, providerResultContract, providerResultShape, questionToSystemOne, raceSignal, rankLedgerCut, readBodyText, readChunks, readFailure, readJudgeOutcome, readProviderDelta, relayFrameContract, relayFrameShape, releaseReader, rememberToolContract, rememberToolShape, removeEntries, renderArguments, renderCauseChain, renderFencedFile, renderIndexEntry, renderIndexLine, renderJSON, renderLedgerAnnotation, renderLedgerPinned, renderLedgerRecord, renderLookupCall, renderSection, renderSkillBody, renderStub, renderToolValue, renderTopicNames, requestToRelay, requireAnswer, requireBudget, requireBuiltins, requireConversation, requireConversationSnapshot, requireCumulative, requireEntry, requireFallback, requireJudgeResult, requireJudgment, requireKeep, requireLimit, requireMessageInput, requireProviderResult, requireRecordInput, requireRole, requireRules, requireScope, requireSectionsCap, requireSummary, requireWorkspace, resolveDecision, resolveDisclosure, resolvePredict, sanitizeToken, sanitizeUsage, scanAmendments, scanJobTree, scanJudgmentTies, scanProbability, sectionContract, sectionShape, selectRecords, settleAgentJob, settleToolResult, skillInputContract, skillInputShape, splitResultLines, splitSentences, splitTopic, splitWords, stripThinking, sumUsage, switchToolContract, switchToolShape, tokenUsageShape, tokenUsageToJSON, toolCallShape };
14816
+ export { AGENT_OPTION_KEYS, AGENT_RUN_KEYS, ARGUMENT_BLANK_PATTERN, ARGUMENT_CONTROL_PATTERN, AUTHORITY_NOTES, AUTHORITY_OPTION_KEYS, Agent, AgentContext, AgentError, AgentFanout, AgentJobError, AgentJudge, AgentProvider, AgentRegistry, Approver, Authority, BUILD_OPTION_KEYS, BUILTIN_LIMITS, BUILTIN_NOTES, BUILTIN_TOOLS, CLASSIFIER_OPTION_KEYS, COMPACT_OPTION_KEYS, CONTEXT_OPTION_KEYS, CONVERSATION_INPUT_KEYS, CONVERSATION_MANAGER_KEYS, CONVERSATION_OPTION_KEYS, CONVERSATION_RECAP_PREFIX, CONVERSATION_ROLES, Channel, Classifier, ContextError, Conversation, ConversationError, ConversationManager, DECISIVE_CATEGORIES, DEFAULT_AGENT_LIMIT, DEFAULT_CONVERSATION_KEEP, DEFAULT_LEDGER_LIMIT, DEFAULT_LEDGER_SHARE, DEFAULT_PROVIDER_TIMEOUT, DEFAULT_RECALL_LIMIT, DEFAULT_RELAY_LIMIT, DETERMINISTIC_JUDGE_ERROR, DatabaseConversationStore, DatabaseMemoStore, GAUGE_OPTION_KEYS, Gauge, IMAGE_TOKEN_ESTIMATE, INSTRUCTION_MANAGER_KEYS, INVALID_RELAY_STATUS, Instruction, InstructionManager, JOB_REFUSAL_PREFIX, JUDGE_INPUT_KEYS, JudgeAbortError, JudgeError, JudgmentManager, LEDGER_AGENT_KEYS, LEDGER_CATEGORIES, LEDGER_NOTES, LEDGER_OPTION_KEYS, LEDGER_OWNER_PREFIX, LEDGER_QUESTIONS, LEDGER_RECALL_LABELS, LEDGER_RULES_KEY, LEDGER_SAMPLE_BYTES, LEDGER_SCALE_DRIFT, LEDGER_SLICE, LEDGER_WORD, LOADED_SECTION_HEADER, Ledger, LedgerError, LedgerRequest, MAX_ERROR_BODY_LENGTH, MEMO_MANAGER_KEYS, MEMO_SECTION_HEADER, MESSAGE_ROLES, MESSAGE_TOKEN_OVERHEAD, MemoManager, MemoryConversationStore, MemoryMemoStore, OVERSIZED_RELAY_STATUS, PLACED_CATEGORIES, PROVIDER_INPUT_KEYS, ProviderAbortError, ProviderError, QUEUE_OPTION_KEYS, QUIET_CATEGORIES, REFERENCE_OPTION_KEYS, REFUSED_RELAY_CONTENT_TYPE, REFUSED_RELAY_STATUS, REGISTRY_OPTION_KEYS, RELAY_CONTENT_TYPE, RELAY_OPTION_KEYS, RELAY_PROVIDER_KEYS, RELAY_PROVIDER_MESSAGE, RELAY_STREAM_KEYS, RUNNER_OPTION_KEYS, RelayProvider, RelayStream, SCOPE_FILTER_KEYS, SCOPE_KEYS, SCOPE_MANAGER_KEYS, SCOPE_NOTE, SKILL_MANAGER_KEYS, SKILL_SECTION_HEADER, STREAM_OPTION_KEYS, SYSTEM_ONE_OPTION_KEYS, SYSTEM_ONE_PATH, Scope, ScopeManager, SkillManager, SystemOneJudge, THINK_CLOSE, THINK_OPEN, ThinkSplitter, UNAUTHORIZED_RELAY_STATUS, UPSTREAM_RELAY_STATUS, WORKSPACE_INDEX_HEADER, WORKSPACE_SECTION_HEADER, agentAnswerContract, agentAnswerShape, agentChunkToFrame, agentFrameContract, agentFrameShape, agentJobContract, agentJobShape, agentPromptContract, agentPromptShape, agentResultToFrame, agentResultToJSON, agentStreamToFrames, armReaderAbort, assembleResult, attachImages, attachUserImages, buildJudgeResult, buildJudgments, buildLedgerCut, buildLedgerIndex, buildLedgerLineKey, buildLedgerRenderContext, buildLines, buildProviderHeaders, buildProviderResult, buildRecallMessage, buildRecapMessage, buildRecords, buildRelayRequest, buildRequestMessage, buildSummaryMessage, builtinToolContracts, chargeUsage, collectAmendments, collectBuiltinDefinitions, collectDisclosure, collectExchanges, collectImageData, collectJobRefusals, collectLedgerEvidence, collectLedgerLines, collectLedgerReplies, collectLive, collectNames, collectProjectionIds, collectRecallMessages, collectRegistry, collectRetiredFindings, collectToolGroups, collectWriteSupersessions, computeLedgerChecksum, computeSkillPrice, computeThinking, computeToolDensity, computeToolPrice, conversationSnapshotContract, conversationSnapshotShape, copyJSON, createAgent, createAgentContext, createAgentQueue, createAgentRegistry, createAgentRunner, createApprover, createAuthority, createBuiltinTool, createChannel, createConversation, createConversationManager, createDatabaseConversationStore, createDatabaseMemoStore, createInstruction, createInstructionManager, createLedger, createMemoManager, createMemoryConversationStore, createMemoryMemoStore, createRelay, createRelayProvider, createScope, createScopeManager, createSkillManager, createSystemOneJudge, createThinkSplitter, cutListing, cutWorkspaceSample, denyCall, describeCandidates, describeQuestionRefusal, describeRelayRefusal, describeSnapshotRefusal, digestLedgerTools, digestLedgerWindow, estimateMessages, estimateRequest, estimateTokens, extractLiterals, extractQueueOptions, extractSystemOneAnswer, extractSystemOneUsage, extractWords, filterAdvertisedTools, filterAllowList, filterBuiltinCandidates, findLedgerCut, findToolCall, fitSlope, freezeJSON, handleAgentQueueJob, hasCalls, hasHiddenRecall, identifyLookup, inferStop, instructionInputContract, instructionInputShape, intersectFilters, intersectKeys, isAgentBuiltin, isAgentCaller, isAgentError, isAgentJobError, isAuthorityDecision, isAuthorityVerdict, isContextError, isConversation, isConversationError, isConversationSnapshot, isFraction, isJudgeAbortError, isJudgeAnswer, isJudgeEntry, isJudgeError, isJudgeQuestion, isJudgment, isLedgerError, isLedgerQuestion, isLedgerSnapshot, isLedgerWindowSnapshot, isMemo, isMemoOrigin, isMemoSnapshot, isMessage, isMessageInput, isNonNegativeSafeInteger, isPositiveSafeInteger, isProviderAbortError, isProviderError, isProviderResult, isScope, isSection, isSystemOneAnswer, isSystemOneResponse, joinThinking, judgeAnswerContract, judgeAnswerShape, judgeEntryShape, judgeQuestionContract, judgeQuestionShape, judgmentContract, judgmentShape, ledgerSnapshotContract, ledgerSnapshotShape, ledgerWindowContract, ledgerWindowShape, linkOwners, loadToolContract, loadToolShape, matchEntities, matchesCutLine, matchesHeadLists, matchesJSON, matchesJudgment, matchesLookup, matchesPlainLine, measureAnswer, measureMessage, measureRequest, memoContract, memoInputContract, memoInputShape, memoShape, memoSnapshotContract, memoSnapshotShape, memoToolContract, memoToolShape, mergeSupersessions, messageContract, messageInputContract, messageInputShape, messageShape, normalizeArgument, normalizeWord, placeMember, providerRequestContract, providerRequestShape, providerResultContract, providerResultShape, questionToSystemOne, raceSignal, rankLedgerCut, readBodyText, readChunks, readFailure, readJudgeOutcome, readProviderDelta, relayFrameContract, relayFrameShape, releaseReader, rememberToolContract, rememberToolShape, removeEntries, renderArguments, renderCauseChain, renderFencedFile, renderIndexEntry, renderIndexLine, renderJSON, renderLedgerAnnotation, renderLedgerPinned, renderLedgerRecord, renderLookupCall, renderSection, renderSkillBody, renderStub, renderToolValue, renderTopicNames, requestToRelay, requireAnswer, requireBudget, requireBuiltins, requireConversation, requireConversationSnapshot, requireCumulative, requireEntry, requireFallback, requireJudgeResult, requireJudgment, requireKeep, requireLimit, requireMessageInput, requireProviderResult, requireRecordInput, requireRole, requireRules, requireScope, requireSectionsCap, requireSummary, requireWorkspace, resolveDecision, resolveDisclosure, resolvePredict, resolveWorkspace, sanitizeToken, sanitizeUsage, scanAmendments, scanJobTree, scanJudgmentTies, scanProbability, sectionContract, sectionShape, selectRecords, settleAgentJob, settleToolResult, skillInputContract, skillInputShape, splitResultLines, splitSentences, splitTopic, splitWords, stripThinking, sumUsage, switchToolContract, switchToolShape, tokenUsageShape, tokenUsageToJSON, toolCallShape };
14725
14817
 
14726
14818
  //# sourceMappingURL=index.js.map