@granular-software/sdk 0.4.36 → 0.4.38

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/README.md CHANGED
@@ -70,7 +70,7 @@ const env = await granular.openEnvironment({
70
70
  ontology: "my-ontology",
71
71
  tag: "dev",
72
72
  userId: "user_123",
73
- permissions: ["agent"],
73
+ permissions: ["allow-all"],
74
74
  name: "Jane Doe", // optional
75
75
  email: "jane@example.com", // optional
76
76
  });
@@ -268,7 +268,7 @@ const env = await granular.openEnvironment({
268
268
  ontology: "library-app",
269
269
  tag: "dev",
270
270
  userId: "user_123",
271
- permissions: ["agent"],
271
+ permissions: ["allow-all"],
272
272
  });
273
273
 
274
274
  const [tolkien, lotr] = await env.recordObjects(
@@ -380,6 +380,86 @@ await granular.ontology(env.sandboxId).effects.registerMany([
380
380
  ]);
381
381
  ```
382
382
 
383
+ ## Permission Profiles and Policies
384
+
385
+ Policies are versioned with the ontology. Author role profiles as JSON files under `permissions/`, then run `granular build` or `granular deploy`; the CLI validates and syncs those files before the build.
386
+
387
+ Built-in profiles are materialized by `granular init` and `granular pull`:
388
+
389
+ - `allow-all`: exposes every declared action unless manifest logic denies it.
390
+ - `confirm-all`: exposes every declared action but requires confirmation.
391
+ - `deny-all`: exposes no executable actions.
392
+
393
+ Manifest-level logic policies live on effects and apply to every profile:
394
+
395
+ ```json
396
+ {
397
+ "withEffect": {
398
+ "name": "approve_ticket",
399
+ "attachedClass": "ticket",
400
+ "inputSchema": { "type": "object", "properties": { "note": { "type": "string" } } },
401
+ "outputSchema": { "type": "object", "properties": { "ok": { "type": "boolean" } } },
402
+ "metamodels": {
403
+ "policies": {
404
+ "denyWhen": [
405
+ {
406
+ "reason": "Locked tickets cannot be approved",
407
+ "when": { "object": { "path": "locked", "operator": "eq", "booleanValue": true } }
408
+ }
409
+ ]
410
+ }
411
+ }
412
+ }
413
+ }
414
+ ```
415
+
416
+ Permission profile files define role-specific access:
417
+
418
+ ```json
419
+ {
420
+ "schemaVersion": 1,
421
+ "name": "reviewer",
422
+ "defaults": { "actionPolicy": "deny" },
423
+ "policies": [
424
+ {
425
+ "action": "approve_ticket",
426
+ "on": "ticket",
427
+ "decision": "allow",
428
+ "reason": "Active low-risk tickets can be approved",
429
+ "when": {
430
+ "all": [
431
+ { "object": { "path": "risk_score", "operator": "lte", "numberValue": 50 } },
432
+ { "stateMachine": { "machine": "lifecycle", "operator": "eq", "stringValue": "active" } }
433
+ ]
434
+ }
435
+ }
436
+ ],
437
+ "actions": [
438
+ { "action": "comment_ticket", "on": "ticket", "allow": "always" }
439
+ ]
440
+ }
441
+ ```
442
+
443
+ Supported profile features:
444
+
445
+ - `defaults.actionPolicy`: `allow`, `confirm`, or `deny` (omitted means `deny`).
446
+ - `extends`: inherit one parent profile; children cannot define `defaults`.
447
+ - `policies[]`: cross-action or targeted rules with `decision` / `outcome` and `when`.
448
+ - `actions[]`: `allow`, `confirm`, `deny`, `allowWhen`, `confirmWhen`, `denyWhen`, and numeric `limits`.
449
+ - Conditions can read `input`, target `object` fields, and target `stateMachine` state, with `all`, `any`, and `not`.
450
+
451
+ Decision precedence is deterministic: manifest deny, profile deny, confirmation rules, profile allow, then the profile default. Runtime blocks denied actions before the effect provider is invoked; confirmation rules use the normal human prompt flow.
452
+
453
+ Useful CLI checks:
454
+
455
+ ```bash
456
+ granular permissions validate
457
+ granular permissions preview --profile reviewer --action approve_ticket --on ticket \
458
+ --input '{"note":"ok"}' \
459
+ --object '{"risk_score":40,"locked":false}' \
460
+ --state-machines '{"lifecycle":"active"}'
461
+ ```
462
+
383
463
  ## Domain Synthesis (Auto-Generated Types)
384
464
 
385
465
  After applying the manifest and publishing tools, the sandbox gets **auto-generated TypeScript classes** in `./sandbox-tools`:
@@ -1,7 +1,9 @@
1
- import { P as Prompt, f as EnvironmentSession, c as SessionHeapSnapshot, bl as ManifestContent, aO as RecordObjectOptions, T as ToolWithHandler, G as Granular, C as ConnectOptions, J as CreateEnvironmentData, k as GranularOptions } from './client-Cq8onk2D.mjs';
2
- import { GeneratedJobCodeIssue, HarnessControllerBudgets } from './agent-harness.mjs';
1
+ import { a as EnvironmentSession, G as Granular } from './client-HDJgcJC5.mjs';
2
+ import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, c as SessionHeapSnapshot, bH as ManifestContent, b5 as RecordObjectOptions, T as ToolWithHandler, C as ConnectOptions, a6 as CreateEnvironmentData, q as GranularOptions } from './spend-rzS1rlFr.mjs';
3
+ import { GranularAgentToolInfo, GeneratedJobCodeIssue, HarnessControllerBudgets } from './agent-harness.mjs';
3
4
  import '@automerge/automerge';
4
5
  import '@automerge/automerge/slim';
6
+ import '@granular-software/policy-engine';
5
7
 
6
8
  type EvalMatcher = string | RegExp;
7
9
  interface AgentEvalPromptInteraction {
@@ -19,12 +21,46 @@ interface AgentEvalGenerationInput {
19
21
  }>;
20
22
  request: string;
21
23
  attempt: number;
24
+ tools?: GranularAgentToolInfo[];
22
25
  repairIssues?: GeneratedJobCodeIssue[];
26
+ onTextDelta?: (delta: string) => void | Promise<void>;
27
+ usageContext?: GranularSpendContext;
23
28
  }
24
29
  interface AgentEvalGenerationOutput {
25
30
  reply?: string;
26
31
  code?: string;
27
32
  raw?: unknown;
33
+ generationAttempts?: AgentEvalGenerationAttempt[];
34
+ }
35
+ interface AgentEvalGenerationAttempt {
36
+ attempt: number;
37
+ request: string;
38
+ repairIssues?: GeneratedJobCodeIssue[];
39
+ reply?: string;
40
+ code?: string;
41
+ raw?: unknown;
42
+ }
43
+ interface AgentEvalTokenUsage {
44
+ calls: number;
45
+ inputTokens: number;
46
+ cachedInputTokens: number;
47
+ uncachedInputTokens: number;
48
+ outputTokens: number;
49
+ totalTokens: number;
50
+ inputCostUsd: number;
51
+ cachedInputCostUsd: number;
52
+ outputCostUsd: number;
53
+ totalCostUsd: number;
54
+ missingUsageCalls: number;
55
+ }
56
+ interface AgentEvalOpenAIUsageEvent extends OpenAITokenSpend {
57
+ spendEventId?: string;
58
+ source: "openai";
59
+ lineItemType: "llm_tokens";
60
+ operation: "chat.completions";
61
+ requestId?: string | null;
62
+ usageContext?: GranularSpendContext;
63
+ rawUsage: unknown;
28
64
  }
29
65
  type AgentEvalTurnGenerator = (input: AgentEvalGenerationInput) => Promise<AgentEvalGenerationOutput>;
30
66
  interface ScriptedPromptRule {
@@ -101,6 +137,8 @@ interface AgentEvalStep {
101
137
  }
102
138
  interface AgentEvalScenario {
103
139
  id: string;
140
+ description?: string;
141
+ jobSource?: "llm" | "hardcoded" | "mixed";
104
142
  request?: string;
105
143
  steps?: AgentEvalStep[];
106
144
  setup?: AgentEvalSetup;
@@ -134,6 +172,7 @@ interface AgentEvalResult {
134
172
  actionSummary: string[];
135
173
  promptInteractions: AgentEvalPromptInteraction[];
136
174
  verification: unknown | null;
175
+ tokenUsage?: AgentEvalTokenUsage;
137
176
  steps?: AgentEvalStepResult[];
138
177
  turnDir: string;
139
178
  error?: string;
@@ -164,6 +203,39 @@ interface AgentEvalConversation {
164
203
  promptEvents: PendingPromptEvent[];
165
204
  artifactDir: string;
166
205
  turnCount: number;
206
+ logTurns: AgentEvalSessionLogTurn[];
207
+ }
208
+ interface AgentEvalSessionLogIteration {
209
+ iteration: number;
210
+ request: string;
211
+ systemPrompt: string;
212
+ generationReply?: string;
213
+ generatedCode?: string;
214
+ rawGeneration?: unknown;
215
+ generationAttempts?: AgentEvalGenerationAttempt[];
216
+ tokenUsage?: AgentEvalTokenUsage;
217
+ responseText?: string;
218
+ terminalKind?: "reply" | "closure";
219
+ actionSummary?: string[];
220
+ promptInteractions?: AgentEvalPromptInteraction[];
221
+ continuation?: unknown;
222
+ result?: unknown;
223
+ error?: string;
224
+ }
225
+ interface AgentEvalSessionLogTurn {
226
+ turnNumber: number;
227
+ turnId: string;
228
+ request: string;
229
+ turnDir: string;
230
+ iterations: AgentEvalSessionLogIteration[];
231
+ completed?: {
232
+ responseText: string;
233
+ terminalKind: "reply" | "closure";
234
+ actionSummary: string[];
235
+ promptInteractions: AgentEvalPromptInteraction[];
236
+ result?: unknown;
237
+ };
238
+ error?: string;
167
239
  }
168
240
  interface AgentEvalPendingTurn {
169
241
  conversation: AgentEvalConversation;
@@ -217,6 +289,8 @@ declare function createOpenAIChatTurnGenerator(options: {
217
289
  baseUrl?: string;
218
290
  temperature?: number;
219
291
  headers?: Record<string, string>;
292
+ usageContext?: GranularSpendContext;
293
+ onUsage?: (usage: AgentEvalOpenAIUsageEvent) => void | Promise<void>;
220
294
  }): AgentEvalTurnGenerator;
221
295
  declare function runAgentEvalSuite(options: {
222
296
  harness: ReturnType<typeof createAgentEvalHarness>;
@@ -318,4 +392,4 @@ declare const createHumanResponder: typeof createScriptedPromptResponder;
318
392
  declare const createOpenAIGenerator: typeof createOpenAIChatTurnGenerator;
319
393
  declare const createTestArtifactsDirectory: typeof createTimestampedArtifactDirectory;
320
394
 
321
- export { type AgentEvalCheck, type AgentEvalCheckContext, type AgentEvalCompletedTurn, type AgentEvalConversation, type AgentEvalExpectations, type AgentEvalGenerationInput, type AgentEvalGenerationOutput, type AgentEvalHarnessOptions, type AgentEvalInspection, type AgentEvalPendingTurn, type AgentEvalPrepareContext, type AgentEvalPromptInteraction, type AgentEvalPromptResponder, type AgentEvalResult, type AgentEvalScenario, type AgentEvalSetup, type AgentEvalSetupContext, type AgentEvalStep, type AgentEvalStepResult, type AgentEvalSuiteResult, type AgentEvalTurnGenerator, type AgentTestTarget, type AgentTesterOptions, type EvalMatcher, type ScriptedPromptRule, createAgentEvalHarness, createAgentTester, createHumanResponder, createOpenAIChatTurnGenerator, createOpenAIGenerator, createScriptedPromptResponder, createTestArtifactsDirectory, createTimestampedArtifactDirectory, runAgentEvalSuite, runAgentTests };
395
+ export { type AgentEvalCheck, type AgentEvalCheckContext, type AgentEvalCompletedTurn, type AgentEvalConversation, type AgentEvalExpectations, type AgentEvalGenerationAttempt, type AgentEvalGenerationInput, type AgentEvalGenerationOutput, type AgentEvalHarnessOptions, type AgentEvalInspection, type AgentEvalOpenAIUsageEvent, type AgentEvalPendingTurn, type AgentEvalPrepareContext, type AgentEvalPromptInteraction, type AgentEvalPromptResponder, type AgentEvalResult, type AgentEvalScenario, type AgentEvalSetup, type AgentEvalSetupContext, type AgentEvalStep, type AgentEvalStepResult, type AgentEvalSuiteResult, type AgentEvalTokenUsage, type AgentEvalTurnGenerator, type AgentTestTarget, type AgentTesterOptions, type EvalMatcher, type ScriptedPromptRule, createAgentEvalHarness, createAgentTester, createHumanResponder, createOpenAIChatTurnGenerator, createOpenAIGenerator, createScriptedPromptResponder, createTestArtifactsDirectory, createTimestampedArtifactDirectory, runAgentEvalSuite, runAgentTests };
@@ -1,7 +1,9 @@
1
- import { P as Prompt, f as EnvironmentSession, c as SessionHeapSnapshot, bl as ManifestContent, aO as RecordObjectOptions, T as ToolWithHandler, G as Granular, C as ConnectOptions, J as CreateEnvironmentData, k as GranularOptions } from './client-Cq8onk2D.js';
2
- import { GeneratedJobCodeIssue, HarnessControllerBudgets } from './agent-harness.js';
1
+ import { a as EnvironmentSession, G as Granular } from './client-BNbWA9jQ.js';
2
+ import { G as GranularSpendContext, h as OpenAITokenSpend, P as Prompt, c as SessionHeapSnapshot, bH as ManifestContent, b5 as RecordObjectOptions, T as ToolWithHandler, C as ConnectOptions, a6 as CreateEnvironmentData, q as GranularOptions } from './spend-rzS1rlFr.js';
3
+ import { GranularAgentToolInfo, GeneratedJobCodeIssue, HarnessControllerBudgets } from './agent-harness.js';
3
4
  import '@automerge/automerge';
4
5
  import '@automerge/automerge/slim';
6
+ import '@granular-software/policy-engine';
5
7
 
6
8
  type EvalMatcher = string | RegExp;
7
9
  interface AgentEvalPromptInteraction {
@@ -19,12 +21,46 @@ interface AgentEvalGenerationInput {
19
21
  }>;
20
22
  request: string;
21
23
  attempt: number;
24
+ tools?: GranularAgentToolInfo[];
22
25
  repairIssues?: GeneratedJobCodeIssue[];
26
+ onTextDelta?: (delta: string) => void | Promise<void>;
27
+ usageContext?: GranularSpendContext;
23
28
  }
24
29
  interface AgentEvalGenerationOutput {
25
30
  reply?: string;
26
31
  code?: string;
27
32
  raw?: unknown;
33
+ generationAttempts?: AgentEvalGenerationAttempt[];
34
+ }
35
+ interface AgentEvalGenerationAttempt {
36
+ attempt: number;
37
+ request: string;
38
+ repairIssues?: GeneratedJobCodeIssue[];
39
+ reply?: string;
40
+ code?: string;
41
+ raw?: unknown;
42
+ }
43
+ interface AgentEvalTokenUsage {
44
+ calls: number;
45
+ inputTokens: number;
46
+ cachedInputTokens: number;
47
+ uncachedInputTokens: number;
48
+ outputTokens: number;
49
+ totalTokens: number;
50
+ inputCostUsd: number;
51
+ cachedInputCostUsd: number;
52
+ outputCostUsd: number;
53
+ totalCostUsd: number;
54
+ missingUsageCalls: number;
55
+ }
56
+ interface AgentEvalOpenAIUsageEvent extends OpenAITokenSpend {
57
+ spendEventId?: string;
58
+ source: "openai";
59
+ lineItemType: "llm_tokens";
60
+ operation: "chat.completions";
61
+ requestId?: string | null;
62
+ usageContext?: GranularSpendContext;
63
+ rawUsage: unknown;
28
64
  }
29
65
  type AgentEvalTurnGenerator = (input: AgentEvalGenerationInput) => Promise<AgentEvalGenerationOutput>;
30
66
  interface ScriptedPromptRule {
@@ -101,6 +137,8 @@ interface AgentEvalStep {
101
137
  }
102
138
  interface AgentEvalScenario {
103
139
  id: string;
140
+ description?: string;
141
+ jobSource?: "llm" | "hardcoded" | "mixed";
104
142
  request?: string;
105
143
  steps?: AgentEvalStep[];
106
144
  setup?: AgentEvalSetup;
@@ -134,6 +172,7 @@ interface AgentEvalResult {
134
172
  actionSummary: string[];
135
173
  promptInteractions: AgentEvalPromptInteraction[];
136
174
  verification: unknown | null;
175
+ tokenUsage?: AgentEvalTokenUsage;
137
176
  steps?: AgentEvalStepResult[];
138
177
  turnDir: string;
139
178
  error?: string;
@@ -164,6 +203,39 @@ interface AgentEvalConversation {
164
203
  promptEvents: PendingPromptEvent[];
165
204
  artifactDir: string;
166
205
  turnCount: number;
206
+ logTurns: AgentEvalSessionLogTurn[];
207
+ }
208
+ interface AgentEvalSessionLogIteration {
209
+ iteration: number;
210
+ request: string;
211
+ systemPrompt: string;
212
+ generationReply?: string;
213
+ generatedCode?: string;
214
+ rawGeneration?: unknown;
215
+ generationAttempts?: AgentEvalGenerationAttempt[];
216
+ tokenUsage?: AgentEvalTokenUsage;
217
+ responseText?: string;
218
+ terminalKind?: "reply" | "closure";
219
+ actionSummary?: string[];
220
+ promptInteractions?: AgentEvalPromptInteraction[];
221
+ continuation?: unknown;
222
+ result?: unknown;
223
+ error?: string;
224
+ }
225
+ interface AgentEvalSessionLogTurn {
226
+ turnNumber: number;
227
+ turnId: string;
228
+ request: string;
229
+ turnDir: string;
230
+ iterations: AgentEvalSessionLogIteration[];
231
+ completed?: {
232
+ responseText: string;
233
+ terminalKind: "reply" | "closure";
234
+ actionSummary: string[];
235
+ promptInteractions: AgentEvalPromptInteraction[];
236
+ result?: unknown;
237
+ };
238
+ error?: string;
167
239
  }
168
240
  interface AgentEvalPendingTurn {
169
241
  conversation: AgentEvalConversation;
@@ -217,6 +289,8 @@ declare function createOpenAIChatTurnGenerator(options: {
217
289
  baseUrl?: string;
218
290
  temperature?: number;
219
291
  headers?: Record<string, string>;
292
+ usageContext?: GranularSpendContext;
293
+ onUsage?: (usage: AgentEvalOpenAIUsageEvent) => void | Promise<void>;
220
294
  }): AgentEvalTurnGenerator;
221
295
  declare function runAgentEvalSuite(options: {
222
296
  harness: ReturnType<typeof createAgentEvalHarness>;
@@ -318,4 +392,4 @@ declare const createHumanResponder: typeof createScriptedPromptResponder;
318
392
  declare const createOpenAIGenerator: typeof createOpenAIChatTurnGenerator;
319
393
  declare const createTestArtifactsDirectory: typeof createTimestampedArtifactDirectory;
320
394
 
321
- export { type AgentEvalCheck, type AgentEvalCheckContext, type AgentEvalCompletedTurn, type AgentEvalConversation, type AgentEvalExpectations, type AgentEvalGenerationInput, type AgentEvalGenerationOutput, type AgentEvalHarnessOptions, type AgentEvalInspection, type AgentEvalPendingTurn, type AgentEvalPrepareContext, type AgentEvalPromptInteraction, type AgentEvalPromptResponder, type AgentEvalResult, type AgentEvalScenario, type AgentEvalSetup, type AgentEvalSetupContext, type AgentEvalStep, type AgentEvalStepResult, type AgentEvalSuiteResult, type AgentEvalTurnGenerator, type AgentTestTarget, type AgentTesterOptions, type EvalMatcher, type ScriptedPromptRule, createAgentEvalHarness, createAgentTester, createHumanResponder, createOpenAIChatTurnGenerator, createOpenAIGenerator, createScriptedPromptResponder, createTestArtifactsDirectory, createTimestampedArtifactDirectory, runAgentEvalSuite, runAgentTests };
395
+ export { type AgentEvalCheck, type AgentEvalCheckContext, type AgentEvalCompletedTurn, type AgentEvalConversation, type AgentEvalExpectations, type AgentEvalGenerationAttempt, type AgentEvalGenerationInput, type AgentEvalGenerationOutput, type AgentEvalHarnessOptions, type AgentEvalInspection, type AgentEvalOpenAIUsageEvent, type AgentEvalPendingTurn, type AgentEvalPrepareContext, type AgentEvalPromptInteraction, type AgentEvalPromptResponder, type AgentEvalResult, type AgentEvalScenario, type AgentEvalSetup, type AgentEvalSetupContext, type AgentEvalStep, type AgentEvalStepResult, type AgentEvalSuiteResult, type AgentEvalTokenUsage, type AgentEvalTurnGenerator, type AgentTestTarget, type AgentTesterOptions, type EvalMatcher, type ScriptedPromptRule, createAgentEvalHarness, createAgentTester, createHumanResponder, createOpenAIChatTurnGenerator, createOpenAIGenerator, createScriptedPromptResponder, createTestArtifactsDirectory, createTimestampedArtifactDirectory, runAgentEvalSuite, runAgentTests };