@agentguard-run/spend 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/LICENSE +53 -0
- package/README.md +76 -0
- package/dist/advisor/conversation.d.ts +5 -0
- package/dist/advisor/conversation.d.ts.map +1 -1
- package/dist/advisor/conversation.js +34 -2
- package/dist/advisor/conversation.js.map +1 -1
- package/dist/advisor/output.d.ts.map +1 -1
- package/dist/advisor/output.js +9 -2
- package/dist/advisor/output.js.map +1 -1
- package/dist/advisor/system-prompt.d.ts.map +1 -1
- package/dist/advisor/system-prompt.js +6 -3
- package/dist/advisor/system-prompt.js.map +1 -1
- package/dist/cli/advisor.d.ts.map +1 -1
- package/dist/cli/advisor.js +11 -2
- package/dist/cli/advisor.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +20 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +19 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/license.d.ts +2 -0
- package/dist/cli/license.d.ts.map +1 -0
- package/dist/cli/license.js +39 -0
- package/dist/cli/license.js.map +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +37 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/skill.d.ts +2 -0
- package/dist/cli/skill.d.ts.map +1 -0
- package/dist/cli/skill.js +33 -0
- package/dist/cli/skill.js.map +1 -0
- package/dist/cli/soft-cap.d.ts +25 -0
- package/dist/cli/soft-cap.d.ts.map +1 -0
- package/dist/cli/soft-cap.js +204 -0
- package/dist/cli/soft-cap.js.map +1 -0
- package/dist/cost-table.d.ts.map +1 -1
- package/dist/cost-table.js +2 -0
- package/dist/cost-table.js.map +1 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -3
- package/dist/index.js.map +1 -1
- package/dist/license.d.ts +44 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +278 -0
- package/dist/license.js.map +1 -0
- package/dist/policy.d.ts +15 -1
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +95 -1
- package/dist/policy.js.map +1 -1
- package/dist/spend-guard.d.ts +10 -0
- package/dist/spend-guard.d.ts.map +1 -1
- package/dist/spend-guard.js +14 -1
- package/dist/spend-guard.js.map +1 -1
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/workflow/chain-validator.d.ts +4 -0
- package/dist/workflow/chain-validator.d.ts.map +1 -0
- package/dist/workflow/chain-validator.js +37 -0
- package/dist/workflow/chain-validator.js.map +1 -0
- package/dist/workflow/context.d.ts +46 -0
- package/dist/workflow/context.d.ts.map +1 -0
- package/dist/workflow/context.js +360 -0
- package/dist/workflow/context.js.map +1 -0
- package/dist/workflow/errors.d.ts +43 -0
- package/dist/workflow/errors.d.ts.map +1 -0
- package/dist/workflow/errors.js +40 -0
- package/dist/workflow/errors.js.map +1 -0
- package/dist/workflow/index.d.ts +6 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +20 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/receipt.d.ts +23 -0
- package/dist/workflow/receipt.d.ts.map +1 -0
- package/dist/workflow/receipt.js +60 -0
- package/dist/workflow/receipt.js.map +1 -0
- package/dist/workflow/types.d.ts +74 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/types.js +3 -0
- package/dist/workflow/types.js.map +1 -0
- package/package.json +11 -4
- package/src/advisor/conversation.ts +41 -2
- package/src/advisor/output.ts +9 -2
- package/src/advisor/system-prompt.ts +6 -3
- package/src/cli/advisor.ts +9 -2
- package/src/cli/auth.ts +19 -1
- package/src/workflow/chain-validator.ts +35 -0
- package/src/workflow/context.ts +418 -0
- package/src/workflow/errors.ts +27 -0
- package/src/workflow/index.ts +18 -0
- package/src/workflow/receipt.ts +73 -0
- package/src/workflow/types.ts +88 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export type WorkflowState = 'active' | 'paused' | 'cancelled' | 'completed' | 'budget_capped' | 'duration_capped';
|
|
2
|
+
export type ReviewerVerdict = 'approve' | 'block' | 'revise' | null;
|
|
3
|
+
export interface WorkflowConfig {
|
|
4
|
+
name: string;
|
|
5
|
+
budget_cap_usd: number;
|
|
6
|
+
duration_cap_hours: number;
|
|
7
|
+
checkpoint_every_outcomes?: number;
|
|
8
|
+
parent_outcomes?: string[];
|
|
9
|
+
resume_if_exists?: boolean;
|
|
10
|
+
metadata?: Record<string, string | number | boolean>;
|
|
11
|
+
user_id?: string;
|
|
12
|
+
api_base_url?: string;
|
|
13
|
+
license_key?: string;
|
|
14
|
+
post_json?: (url: string, body: unknown, headers: Record<string, string>) => Promise<unknown>;
|
|
15
|
+
get_json?: (url: string, headers: Record<string, string>) => Promise<unknown>;
|
|
16
|
+
}
|
|
17
|
+
export interface ReviewerCascadeEvidence {
|
|
18
|
+
triggered: boolean;
|
|
19
|
+
drafter_model: string | null;
|
|
20
|
+
reviewer_model: string | null;
|
|
21
|
+
drafter_output_hash: string | null;
|
|
22
|
+
reviewer_verdict: ReviewerVerdict;
|
|
23
|
+
reviewer_reasoning_hash: string | null;
|
|
24
|
+
review_started_at: string | null;
|
|
25
|
+
review_completed_at: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface ReceiptV2 {
|
|
28
|
+
receipt_id: string;
|
|
29
|
+
schema_version: 2;
|
|
30
|
+
outcome_name: string;
|
|
31
|
+
user_id: string;
|
|
32
|
+
cost_usd: number;
|
|
33
|
+
signed_at: string;
|
|
34
|
+
signature: string;
|
|
35
|
+
public_key_fingerprint: string;
|
|
36
|
+
workflow_id: string | null;
|
|
37
|
+
parent_receipt_id: string | null;
|
|
38
|
+
chain_validation_hash: string | null;
|
|
39
|
+
workflow_checkpoint_idx: number | null;
|
|
40
|
+
workflow_total_spend_usd_to_date: number | null;
|
|
41
|
+
is_checkpoint: boolean;
|
|
42
|
+
checkpoint_label: string | null;
|
|
43
|
+
reviewer_cascade: ReviewerCascadeEvidence | null;
|
|
44
|
+
receipt_type?: 'outcome' | 'checkpoint' | 'cancel' | 'cap_hit' | 'completed';
|
|
45
|
+
cancelled_reason?: string | null;
|
|
46
|
+
}
|
|
47
|
+
export interface CheckpointReceipt extends ReceiptV2 {
|
|
48
|
+
is_checkpoint: true;
|
|
49
|
+
}
|
|
50
|
+
export interface WorkflowStatus {
|
|
51
|
+
workflow_id: string;
|
|
52
|
+
state: WorkflowState;
|
|
53
|
+
total_spend_usd: number;
|
|
54
|
+
budget_cap_usd: number;
|
|
55
|
+
budget_remaining_usd: number;
|
|
56
|
+
budget_pct_used: number;
|
|
57
|
+
outcome_count: number;
|
|
58
|
+
last_receipt_id: string | null;
|
|
59
|
+
last_checkpoint_id: string | null;
|
|
60
|
+
last_chain_hash: string | null;
|
|
61
|
+
duration_elapsed_ms: number;
|
|
62
|
+
duration_cap_ms: number;
|
|
63
|
+
duration_remaining_ms: number;
|
|
64
|
+
}
|
|
65
|
+
export interface ValidationResult {
|
|
66
|
+
ok: true;
|
|
67
|
+
}
|
|
68
|
+
export interface ValidationFailure {
|
|
69
|
+
ok: false;
|
|
70
|
+
broken_at: number;
|
|
71
|
+
reason: 'signature_invalid' | 'chain_hash_mismatch' | 'parent_reference_mismatch';
|
|
72
|
+
}
|
|
73
|
+
export type ChainValidationResult = ValidationResult | ValidationFailure;
|
|
74
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/workflow/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/workflow/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentguard-run/spend",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "All terminology and labels used in AgentGuard materials are descriptive of software functionality only, not legal definitions or guarantees of compliance. Terms like receipt, audit log, evidence, audit trail, and attestation refer solely to cryptographically-signed records produced by the software. Full functional-use disclaimer in README.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -44,6 +44,11 @@
|
|
|
44
44
|
"types": "./dist/advisor/conversation.d.ts",
|
|
45
45
|
"require": "./dist/advisor/conversation.js",
|
|
46
46
|
"default": "./dist/advisor/conversation.js"
|
|
47
|
+
},
|
|
48
|
+
"./workflow": {
|
|
49
|
+
"types": "./dist/workflow/index.d.ts",
|
|
50
|
+
"require": "./dist/workflow/index.js",
|
|
51
|
+
"default": "./dist/workflow/index.js"
|
|
47
52
|
}
|
|
48
53
|
},
|
|
49
54
|
"bin": {
|
|
@@ -65,7 +70,8 @@
|
|
|
65
70
|
"src/cli/wizard.ts",
|
|
66
71
|
"src/bindings",
|
|
67
72
|
"src/advisor",
|
|
68
|
-
"src/cli/advisor.ts"
|
|
73
|
+
"src/cli/advisor.ts",
|
|
74
|
+
"src/workflow"
|
|
69
75
|
],
|
|
70
76
|
"scripts": {
|
|
71
77
|
"build": "tsc",
|
|
@@ -103,7 +109,8 @@
|
|
|
103
109
|
"url": "https://agentguard.run/contact"
|
|
104
110
|
},
|
|
105
111
|
"dependencies": {
|
|
106
|
-
"@noble/ed25519": "
|
|
112
|
+
"@noble/ed25519": "^3.1.0",
|
|
113
|
+
"@noble/hashes": "^2.2.0"
|
|
107
114
|
},
|
|
108
115
|
"peerDependencies": {
|
|
109
116
|
"@anthropic-ai/sdk": ">=0.30.0",
|
|
@@ -38,6 +38,9 @@ export interface AdvisorBusinessProfile {
|
|
|
38
38
|
requiredCapability: CapabilityTier;
|
|
39
39
|
primaryModel: string;
|
|
40
40
|
fallbackModel: string;
|
|
41
|
+
hostedOssModel: string;
|
|
42
|
+
offlineModel: string;
|
|
43
|
+
baaCoveredModel: string;
|
|
41
44
|
perCallCapCents: number;
|
|
42
45
|
perDayCapCents: number;
|
|
43
46
|
perMonthCapCents: number;
|
|
@@ -70,8 +73,40 @@ export const ADVISOR_QUESTIONS: AdvisorQuestion[] = [
|
|
|
70
73
|
{ id: 'confirm', prompt: 'Confirm the setup or list any refinements before I write policy.yaml and quickstart code.' },
|
|
71
74
|
];
|
|
72
75
|
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
const CHINESE_ORIGIN_MODEL_PATTERNS = [/kimi/i, /qwen/i, /deepseek/i, /(^|\/)yi([-/]|$)/i, /01-ai/i];
|
|
79
|
+
const HOSTED_OSS_DEFAULT = 'baseten/llama-4';
|
|
80
|
+
const HOSTED_OSS_VELOCITY = 'baseten/llama-4-13b';
|
|
81
|
+
const OFFLINE_DEFAULT = 'offline/llama-4-m4-ultra';
|
|
82
|
+
const BAA_COVERED_DEFAULT = 'anthropic.claude-sonnet-4-v1:0';
|
|
83
|
+
|
|
84
|
+
export function isChineseOriginModel(model: string): boolean {
|
|
85
|
+
return CHINESE_ORIGIN_MODEL_PATTERNS.some((pattern) => pattern.test(model));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function enforceAdvisorModelPolicy(model: string, posture: GovernancePosture, replacement = 'anthropic/claude-haiku-4-5'): string {
|
|
89
|
+
if (posture === 'compliance' && isChineseOriginModel(model)) {
|
|
90
|
+
console.warn(`AgentGuard Advisor blocked ${model} for compliance posture and selected ${replacement}.`);
|
|
91
|
+
return replacement;
|
|
92
|
+
}
|
|
93
|
+
return model;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function defaultModelsFor(vertical: string, hint: { primary: string; fallback: string }, posture: GovernancePosture): { primary: string; fallback: string; hostedOss: string; offline: string; baaCovered: string } {
|
|
97
|
+
if (posture === 'velocity') {
|
|
98
|
+
return { primary: HOSTED_OSS_VELOCITY, fallback: 'anthropic/claude-haiku-4-5', hostedOss: HOSTED_OSS_VELOCITY, offline: OFFLINE_DEFAULT, baaCovered: BAA_COVERED_DEFAULT };
|
|
99
|
+
}
|
|
100
|
+
if (posture === 'compliance') {
|
|
101
|
+
const regulatedPrimary = vertical === 'accounting' ? 'openai/gpt-5' : vertical === 'real-estate' ? 'google/gemini-3.1-pro-preview' : 'anthropic/claude-opus-4-7';
|
|
102
|
+
return { primary: regulatedPrimary, fallback: 'anthropic/claude-sonnet-4-6', hostedOss: HOSTED_OSS_DEFAULT, offline: OFFLINE_DEFAULT, baaCovered: BAA_COVERED_DEFAULT };
|
|
103
|
+
}
|
|
104
|
+
return { primary: hint.primary, fallback: HOSTED_OSS_DEFAULT, hostedOss: HOSTED_OSS_DEFAULT, offline: OFFLINE_DEFAULT, baaCovered: BAA_COVERED_DEFAULT };
|
|
105
|
+
}
|
|
106
|
+
|
|
73
107
|
const VERTICAL_HINTS: Array<{ vertical: string; needles: string[]; scopeLabel: string; capability: CapabilityTier; primary: string; fallback: string; perCall: number }> = [
|
|
74
108
|
{ vertical: 'law-firm', needles: ['law', 'legal', 'attorney', 'paralegal', 'contract', 'matter', 'discovery'], scopeLabel: 'matter', capability: 'data_write', primary: 'anthropic/claude-sonnet-4-6', fallback: 'anthropic/claude-haiku-4-5', perCall: 300 },
|
|
109
|
+
{ vertical: 'insurance', needles: ['insurance', 'carrier', 'producer', 'agency', 'policy comparison', 'quote letter', 'certificate of insurance', 'renewal', 'e&o'], scopeLabel: 'policy', capability: 'data_write', primary: 'anthropic/claude-sonnet-4-6', fallback: 'baseten/llama-4', perCall: 150 },
|
|
75
110
|
{ vertical: 'healthcare', needles: ['health', 'medical', 'dental', 'clinic', 'patient', 'chart', 'hipaa', 'encounter'], scopeLabel: 'encounter', capability: 'data_write', primary: 'anthropic.claude-sonnet-4-v1:0', fallback: 'amazon.nova-lite-v1:0', perCall: 300 },
|
|
76
111
|
{ vertical: 'ecommerce', needles: ['shopify', 'commerce', 'store', 'order', 'refund', 'chargeback', 'fraud', 'returns'], scopeLabel: 'order', capability: 'payment_initiate', primary: 'openai/gpt-5-mini', fallback: 'openai/gpt-4o-mini', perCall: 25 },
|
|
77
112
|
{ vertical: 'accounting', needles: ['accounting', 'bookkeeping', 'tax', 'ledger', 'receipt', 'close', 'audit', 'sox'], scopeLabel: 'engagement', capability: 'data_write', primary: 'anthropic/claude-sonnet-4-6', fallback: 'anthropic/claude-haiku-4-5', perCall: 150 },
|
|
@@ -157,6 +192,7 @@ export function buildBusinessProfile(answers: AdvisorAnswers, cwd = process.cwd(
|
|
|
157
192
|
const tasks = parseTasks(answers.tasks ?? answers.building ?? hint.vertical);
|
|
158
193
|
const perMonthCapCents = Math.max(1000, budgetCents);
|
|
159
194
|
const perDayCapCents = Math.max(hint.perCall * 10, Math.ceil(perMonthCapCents / 20));
|
|
195
|
+
const models = defaultModelsFor(hint.vertical, hint, posture);
|
|
160
196
|
return {
|
|
161
197
|
vertical: hint.vertical,
|
|
162
198
|
tenantId: tenantIdFromBusiness(answers.building ?? hint.vertical),
|
|
@@ -165,8 +201,11 @@ export function buildBusinessProfile(answers: AdvisorAnswers, cwd = process.cwd(
|
|
|
165
201
|
tasks,
|
|
166
202
|
monthlyBudgetCents: perMonthCapCents,
|
|
167
203
|
requiredCapability: capabilityFor(joined, hint.capability, posture),
|
|
168
|
-
primaryModel:
|
|
169
|
-
fallbackModel:
|
|
204
|
+
primaryModel: enforceAdvisorModelPolicy(models.primary, posture),
|
|
205
|
+
fallbackModel: enforceAdvisorModelPolicy(models.fallback, posture),
|
|
206
|
+
hostedOssModel: enforceAdvisorModelPolicy(models.hostedOss, posture),
|
|
207
|
+
offlineModel: models.offline,
|
|
208
|
+
baaCoveredModel: enforceAdvisorModelPolicy(models.baaCovered, posture),
|
|
170
209
|
perCallCapCents: hint.perCall,
|
|
171
210
|
perDayCapCents,
|
|
172
211
|
perMonthCapCents,
|
package/src/advisor/output.ts
CHANGED
|
@@ -120,6 +120,10 @@ requiredCapability: ${policy.requiredCapability ?? 'read_only'}
|
|
|
120
120
|
scope:
|
|
121
121
|
tenantId: ${quoteYaml(policy.scope.tenantId)}
|
|
122
122
|
models:
|
|
123
|
+
cloudFrontierPrimary: ${profile.primaryModel}
|
|
124
|
+
hostedOssFallback: ${profile.hostedOssModel}
|
|
125
|
+
offlineOption: ${profile.offlineModel}
|
|
126
|
+
baaCoveredOption: ${profile.baaCoveredModel}
|
|
123
127
|
primary: ${profile.primaryModel}
|
|
124
128
|
fallback: ${profile.fallbackModel}
|
|
125
129
|
governancePosture:
|
|
@@ -127,7 +131,10 @@ governancePosture:
|
|
|
127
131
|
auditRetentionDays: ${posture.auditRetentionDays}
|
|
128
132
|
approvalGates: ${posture.approvalGates}
|
|
129
133
|
downgradeStyle: ${posture.downgradeStyle}
|
|
130
|
-
${canary}
|
|
134
|
+
${canary}reviewerCascade:
|
|
135
|
+
default: ${profile.posture === 'compliance' ? 'always' : 'risk_triggered'}
|
|
136
|
+
triageClassifier: local-3b
|
|
137
|
+
tasks:
|
|
131
138
|
${tasks}
|
|
132
139
|
caps:
|
|
133
140
|
${caps}
|
|
@@ -180,7 +187,7 @@ function whyForWindow(window: string): string {
|
|
|
180
187
|
|
|
181
188
|
function systemInstructions(profile: AdvisorBusinessProfile): string {
|
|
182
189
|
const posture = postureProfile(profile.posture);
|
|
183
|
-
return `Run ${profile.vertical} tasks with ${profile.requiredCapability} capability under ${posture.label} governance posture. Prefer ${profile.primaryModel} for high-value work
|
|
190
|
+
return `Run ${profile.vertical} tasks with ${profile.requiredCapability} capability under ${posture.label} governance posture. Prefer ${profile.primaryModel} for high-value work, ${profile.hostedOssModel} for hosted OSS fallback, ${profile.offlineModel} for offline runs, and ${profile.baaCoveredModel} when a BAA-covered provider is required. Keep evidence pointers in outputs and escalate anything outside the configured capability tier.`;
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
function quoteYaml(value: string): string {
|
|
@@ -70,7 +70,9 @@ Standard: default for most SaaS, e-commerce, real estate, agencies, local servic
|
|
|
70
70
|
|
|
71
71
|
Compliance: for law, healthcare, dental, accounting, SOX, fintech, and regulated workflows. Default mode is canary, meaning enforce with a 5 percent sticky shadow sample. Capabilities are strict, with payment_execute for financial workflows and data_write minimum for PHI or PII workflows. Downgrade chains are conservative, and regulated capabilities block instead of downgrade. Audit retention is 7 years. Per-action approval gates are on for payment_execute.
|
|
72
72
|
|
|
73
|
-
Custom: a Solo tier posture for future Outcome Builder workflows. In this release, tell the user Solo tier is required and choose Velocity, Standard, or Compliance instead
|
|
73
|
+
Custom: a Solo tier posture for future Outcome Builder workflows. In this release, tell the user Solo tier is required and choose Velocity, Standard, or Compliance instead.
|
|
74
|
+
|
|
75
|
+
Chinese-origin model block for compliance posture: do not recommend Kimi K2, Qwen, DeepSeek, Yi, 01.AI, or hosted derivatives of those families for regulated or sensitive workflows. The block applies to cloud-frontier routes and hosted-OSS routes. If a user asks for one, state that Advisor cannot select it for compliance posture and offer Claude, GPT, Gemini, Llama on Baseten, Azure OpenAI, AWS Bedrock, Google Vertex, or Amazon Q instead.`,
|
|
74
76
|
},
|
|
75
77
|
|
|
76
78
|
{
|
|
@@ -80,7 +82,7 @@ Custom: a Solo tier posture for future Outcome Builder workflows. In this releas
|
|
|
80
82
|
|
|
81
83
|
Law firms. Default posture: compliance. Pricing anchor: Solo $49 is about one Clio EasyStart seat. Startup $199 is below one CoCounsel seat. Growth $999 is a fraction of one Harvey seat. Outcomes: contract redlined, cap $2.00, model anthropic/claude-sonnet-4-6, tier data_write. Research memo delivered, cap $3.00, model anthropic/claude-opus-4-7, tier read_only. Matter intake closed, cap $1.50, model anthropic/claude-haiku-4-5, tier data_write. Deposition pack assembled, cap $5.00, model anthropic/claude-opus-4-7, tier read_only. Brief or motion drafted, cap $7.50, model anthropic/claude-opus-4-7, tier data_write. Compliance citations: ABA Model Rule 1.1 competence, ABA Model Rule 1.6 confidentiality, ABA Formal Opinion 512 on generative AI.
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
Insurance agencies. Default posture: compliance. Pricing anchor: Solo $49 is about half a HawkSoft seat at $94 per user. Outcomes: quote letter drafted, cap $0.50, model anthropic/claude-haiku-4-5, tier data_write. Policy comparison generated, cap $1.50, model anthropic/claude-sonnet-4-6, tier data_write. Certificate of insurance issued, cap $0.25, model anthropic/claude-haiku-4-5, tier data_write. Renewal outreach completed, cap $0.15, model anthropic/claude-haiku-4-5, tier data_write. Inbound lead qualified, cap $0.30, model openai/gpt-5-mini, tier data_write. Reviewer Cascade always runs for policy comparisons, quote letters, and claims correspondence. Compliance citations: NAIC Model Bulletin on AI systems, 11 NYCRR section 215.13, Verisk CG 40 47 and CG 40 48 AI exclusions.
|
|
84
86
|
|
|
85
87
|
Accounting and bookkeeping. Default posture: compliance. Pricing anchor: Solo $49 is about one QuickBooks or low-end practice seat. Startup $199 is below four Karbon Team seats. Growth $999 fits a 10 to 15 staff firm. Outcomes: bookkeeping cycle closed, cap $5.00, model anthropic/claude-haiku-4-5, tier data_write. Tax return drafted, cap $7.50, model openai/gpt-5, tier data_write. IRS or state notice response, cap $3.00, model anthropic/claude-sonnet-4-6, tier data_write. Client email resolved, cap $0.50, model anthropic/claude-haiku-4-5, tier data_write. Workpaper completed, cap $4.00, model openai/gpt-5, tier data_write. Compliance citations: PCAOB AS 1215 audit documentation retention, SOX 802 and 18 U.S.C. 1519 record preservation, GLBA Safeguards Rule 16 CFR Part 314.
|
|
86
88
|
|
|
@@ -96,7 +98,7 @@ Real estate and mortgage. Default posture: standard. Pricing anchor: Solo $49 is
|
|
|
96
98
|
Law firm:
|
|
97
99
|
Tasks: contract redline, novel contract review, legal research, brief drafting, deposition prep, discovery review. Models: anthropic/claude-haiku-4-5 for boilerplate and discovery, anthropic/claude-sonnet-4-6 for research and novel terms, anthropic/claude-opus-4-7 for brief drafting and deposition analysis. Caps: $0.25 discovery tagging, $1 contract redline, $3 novel review, $4 legal research, $8 brief drafting. Scope key: matter or client matter code in agentId, attorney in userId. Compliance: privilege workflows need zero proxy, per-matter accounting, jurisdiction-aware model allowlists, and signed decision receipts for audit packets.
|
|
98
100
|
|
|
99
|
-
Healthcare:
|
|
101
|
+
Healthcare partner-only:
|
|
100
102
|
Tasks: patient triage, chart review, clinical documentation drafting, prior authorization narrative, medical literature search, patient education, insurance verification, appointment scheduling. Models: BAA-covered Bedrock Anthropic for PHI, OpenRouter openai/gpt-5-mini or anthropic/claude-haiku-4-5 for non-PHI. Caps: $0.10 education, $0.25 insurance verification, $0.50 triage, $2 chart review, $3 documentation, $5 prior authorization. Scope key: encounter or patient encounter in agentId, clinician in userId. Compliance: PHI workflows require data_write minimum plus provider BAA controls. Non-PHI can use OpenRouter.
|
|
101
103
|
|
|
102
104
|
E-commerce:
|
|
@@ -160,6 +162,7 @@ anthropic.claude-opus-4-v1:0: input $15.00, output $75.00.
|
|
|
160
162
|
anthropic.claude-sonnet-4-v1:0: input $3.00, output $15.00.
|
|
161
163
|
amazon.nova-pro-v1:0: input $0.80, output $3.20.
|
|
162
164
|
amazon.nova-lite-v1:0: input $0.06, output $0.24.
|
|
165
|
+
Baseten hosted OSS default: baseten/llama-4 at $0.108 per H100-hour as a cost-best hosted fallback. Velocity posture may use baseten/llama-4-13b as primary with anthropic/claude-haiku-4-5 as fallback. Compliance posture uses a cloud frontier primary such as anthropic/claude-opus-4-7, openai/gpt-5, or google/gemini-3.1-pro-preview, with Reviewer Cascade always triggered for regulated outcomes. Offline options are Llama-4 on M4 Ultra or dual H100. BAA-covered options are Azure OpenAI, AWS Bedrock, Google Vertex, and Amazon Q.
|
|
163
166
|
For unknown live OpenRouter models, ask the customer to run agentguard models --sync-pricing before using them in a policy.`,
|
|
164
167
|
},
|
|
165
168
|
{
|
package/src/cli/advisor.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { readDecisionSpend, reviewAnomalies } from '../advisor/anomaly';
|
|
|
12
12
|
import { ADVISOR_SYSTEM_PROMPT } from '../advisor/system-prompt';
|
|
13
13
|
import { createAdvisorSessionLogger, writeAdvisorOutputs } from '../advisor/output';
|
|
14
14
|
import { banner, cyanBold, dim, green, yellow } from './colors';
|
|
15
|
+
import { confirmPostureSoftCap } from './soft-cap';
|
|
15
16
|
|
|
16
17
|
interface AdvisorCliOptions {
|
|
17
18
|
provider: AdvisorProvider;
|
|
@@ -48,8 +49,14 @@ export async function runAdvisor(argv: string[]): Promise<number> {
|
|
|
48
49
|
|
|
49
50
|
const options = parseOptions(argv);
|
|
50
51
|
if (options.posture === 'custom') {
|
|
51
|
-
|
|
52
|
-
return 0;
|
|
52
|
+
const ok = await confirmPostureSoftCap('custom', { yes: options.yes || options.defaults });
|
|
53
|
+
if (!ok) return 0;
|
|
54
|
+
options.posture = 'standard';
|
|
55
|
+
}
|
|
56
|
+
if (options.posture && options.posture !== 'standard' && !process.env.AGENTGUARD_LICENSE_KEY) {
|
|
57
|
+
const ok = await confirmPostureSoftCap(options.posture, { yes: options.yes || options.defaults });
|
|
58
|
+
if (!ok) return 0;
|
|
59
|
+
options.posture = 'standard';
|
|
53
60
|
}
|
|
54
61
|
const apiKey = resolveAdvisorApiKey(options.provider);
|
|
55
62
|
if (options.provider !== 'mock' && !apiKey) {
|
package/src/cli/auth.ts
CHANGED
|
@@ -5,6 +5,7 @@ import * as https from 'https';
|
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import * as readline from 'readline';
|
|
7
7
|
import { AGENTGUARD_SPEND_VERSION } from '../index';
|
|
8
|
+
import { licenseKeyFingerprint, readConfiguredLicenseKey, writeConfiguredLicenseKey } from '../license';
|
|
8
9
|
import { agentguardHome, banner, dim, green, statusBar, yellow } from './colors';
|
|
9
10
|
|
|
10
11
|
const OPENROUTER_AUTH_URL = 'https://openrouter.ai/api/v1/auth/key';
|
|
@@ -50,11 +51,12 @@ export function writeOpenRouterKey(key: string): void {
|
|
|
50
51
|
|
|
51
52
|
export async function runAuth(argv: string[]): Promise<number> {
|
|
52
53
|
if (argv.includes('--help') || argv.includes('-h')) {
|
|
53
|
-
console.log('agentguard auth openrouter | status | clear openrouter');
|
|
54
|
+
console.log('agentguard auth openrouter | license-key <KEY> | status | clear openrouter');
|
|
54
55
|
return 0;
|
|
55
56
|
}
|
|
56
57
|
const sub = argv[0] ?? 'status';
|
|
57
58
|
if (sub === 'status') return authStatus();
|
|
59
|
+
if (sub === 'license-key') return configureLicenseKey(argv[1]);
|
|
58
60
|
if (sub === 'clear' && argv[1] === 'openrouter') return clearOpenRouter();
|
|
59
61
|
if (sub === 'openrouter') return configureOpenRouter(argv);
|
|
60
62
|
console.error(`agentguard auth: unknown command '${argv.join(' ')}'`);
|
|
@@ -93,12 +95,28 @@ function authStatus(): number {
|
|
|
93
95
|
} else {
|
|
94
96
|
console.log(` ${yellow('openrouter')} not configured`);
|
|
95
97
|
}
|
|
98
|
+
const licenseKey = readConfiguredLicenseKey();
|
|
99
|
+
if (licenseKey) {
|
|
100
|
+
console.log(` ${green('license')} configured fingerprint ${licenseKeyFingerprint(licenseKey)}`);
|
|
101
|
+
} else {
|
|
102
|
+
console.log(` ${yellow('license')} free tier`);
|
|
103
|
+
}
|
|
96
104
|
console.log('');
|
|
97
105
|
console.log(' ' + statusBar());
|
|
98
106
|
console.log('');
|
|
99
107
|
return 0;
|
|
100
108
|
}
|
|
101
109
|
|
|
110
|
+
function configureLicenseKey(key?: string): number {
|
|
111
|
+
if (!key?.trim()) {
|
|
112
|
+
console.error('Usage: agentguard auth license-key <KEY>');
|
|
113
|
+
return 2;
|
|
114
|
+
}
|
|
115
|
+
writeConfiguredLicenseKey(key);
|
|
116
|
+
console.log(`License key saved. fingerprint ${licenseKeyFingerprint(key)}`);
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
102
120
|
function clearOpenRouter(): number {
|
|
103
121
|
try { fs.unlinkSync(openRouterKeyPath()); } catch { return 0; }
|
|
104
122
|
console.log('OpenRouter key removed.');
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { canonicalJSONStringify, sha256, verifyReceipt } from './receipt';
|
|
2
|
+
import type { ChainValidationResult, ReceiptV2 } from './types';
|
|
3
|
+
|
|
4
|
+
export async function validateReceiptChain(receipts: ReceiptV2[]): Promise<ChainValidationResult> {
|
|
5
|
+
if (receipts.length === 0) return { ok: true };
|
|
6
|
+
|
|
7
|
+
for (let i = 0; i < receipts.length; i++) {
|
|
8
|
+
if (!verifyReceipt(receipts[i]!)) {
|
|
9
|
+
return { ok: false, broken_at: i, reason: 'signature_invalid' };
|
|
10
|
+
}
|
|
11
|
+
if (i === 0) continue;
|
|
12
|
+
const prev = receipts[i - 1]!;
|
|
13
|
+
const curr = receipts[i]!;
|
|
14
|
+
const expectedHash = await computeChainHash(prev);
|
|
15
|
+
if (curr.chain_validation_hash !== expectedHash) {
|
|
16
|
+
return { ok: false, broken_at: i, reason: 'chain_hash_mismatch' };
|
|
17
|
+
}
|
|
18
|
+
if (curr.parent_receipt_id !== prev.receipt_id) {
|
|
19
|
+
return { ok: false, broken_at: i, reason: 'parent_reference_mismatch' };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return { ok: true };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function computeChainHash(receipt: ReceiptV2): Promise<string> {
|
|
27
|
+
const canonical = canonicalJSONStringify({
|
|
28
|
+
receipt_id: receipt.receipt_id,
|
|
29
|
+
workflow_id: receipt.workflow_id,
|
|
30
|
+
cost_usd: receipt.cost_usd,
|
|
31
|
+
signed_at: receipt.signed_at,
|
|
32
|
+
signature: receipt.signature,
|
|
33
|
+
});
|
|
34
|
+
return sha256(canonical);
|
|
35
|
+
}
|