@ddwang/magnitude-core 0.3.1-ddwang.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions/desktopActions.d.ts +58 -0
- package/dist/actions/desktopActions.js +154 -0
- package/dist/actions/index.d.ts +26 -0
- package/dist/actions/index.js +11 -0
- package/dist/actions/taskActions.d.ts +8 -0
- package/dist/actions/taskActions.js +27 -0
- package/dist/actions/types.d.ts +31 -0
- package/dist/actions/types.js +5 -0
- package/dist/actions/util.d.ts +20 -0
- package/dist/actions/util.js +297 -0
- package/dist/actions/webActions.d.ts +79 -0
- package/dist/actions/webActions.js +190 -0
- package/dist/agent/browserAgent.d.ts +29 -0
- package/dist/agent/browserAgent.js +122 -0
- package/dist/agent/errors.d.ts +8 -0
- package/dist/agent/errors.js +68 -0
- package/dist/agent/index.d.ts +53 -0
- package/dist/agent/index.js +377 -0
- package/dist/agent/narrator.d.ts +4 -0
- package/dist/agent/narrator.js +63 -0
- package/dist/agent/pause.test.d.ts +1 -0
- package/dist/agent/pause.test.js +194 -0
- package/dist/ai/baml_client/async_client.d.ts +73 -0
- package/dist/ai/baml_client/async_client.js +152 -0
- package/dist/ai/baml_client/async_request.d.ts +35 -0
- package/dist/ai/baml_client/async_request.js +98 -0
- package/dist/ai/baml_client/config.d.ts +11 -0
- package/dist/ai/baml_client/config.js +20 -0
- package/dist/ai/baml_client/globals.d.ts +16 -0
- package/dist/ai/baml_client/globals.js +37 -0
- package/dist/ai/baml_client/index.d.ts +16 -0
- package/dist/ai/baml_client/index.js +41 -0
- package/dist/ai/baml_client/inlinedbaml.d.ts +19 -0
- package/dist/ai/baml_client/inlinedbaml.js +31 -0
- package/dist/ai/baml_client/parser.d.ts +53 -0
- package/dist/ai/baml_client/parser.js +86 -0
- package/dist/ai/baml_client/partial_types.d.ts +61 -0
- package/dist/ai/baml_client/partial_types.js +10 -0
- package/dist/ai/baml_client/sync_client.d.ts +50 -0
- package/dist/ai/baml_client/sync_client.js +100 -0
- package/dist/ai/baml_client/sync_request.d.ts +35 -0
- package/dist/ai/baml_client/sync_request.js +98 -0
- package/dist/ai/baml_client/tracing.d.ts +16 -0
- package/dist/ai/baml_client/tracing.js +18 -0
- package/dist/ai/baml_client/type_builder.d.ts +38 -0
- package/dist/ai/baml_client/type_builder.js +96 -0
- package/dist/ai/baml_client/types.d.ts +69 -0
- package/dist/ai/baml_client/types.js +15 -0
- package/dist/ai/claudeCode.d.ts +1 -0
- package/dist/ai/claudeCode.js +186 -0
- package/dist/ai/modelHarness.d.ts +39 -0
- package/dist/ai/modelHarness.js +189 -0
- package/dist/ai/multiModelHarness.d.ts +27 -0
- package/dist/ai/multiModelHarness.js +52 -0
- package/dist/ai/types.d.ts +90 -0
- package/dist/ai/types.js +5 -0
- package/dist/ai/util.d.ts +13 -0
- package/dist/ai/util.js +165 -0
- package/dist/cli.d.ts +0 -0
- package/dist/cli.js +3 -0
- package/dist/common/actions.d.ts +0 -0
- package/dist/common/actions.js +14 -0
- package/dist/common/events.d.ts +15 -0
- package/dist/common/events.js +3 -0
- package/dist/common/failure.d.ts +68 -0
- package/dist/common/failure.js +1 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.js +3 -0
- package/dist/common/retry.d.ts +16 -0
- package/dist/common/retry.js +30 -0
- package/dist/common/util.d.ts +23 -0
- package/dist/common/util.js +132 -0
- package/dist/connectors/browserConnector.d.ts +40 -0
- package/dist/connectors/browserConnector.js +127 -0
- package/dist/connectors/desktopConnector.d.ts +58 -0
- package/dist/connectors/desktopConnector.js +68 -0
- package/dist/connectors/index.d.ts +10 -0
- package/dist/connectors/index.js +2 -0
- package/dist/index.cjs +6143 -0
- package/dist/index.d.cts +825 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +26 -0
- package/dist/index.mjs +6097 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +15 -0
- package/dist/memory/agentMemory.d.ts +37 -0
- package/dist/memory/agentMemory.js +121 -0
- package/dist/memory/image.d.ts +26 -0
- package/dist/memory/image.js +106 -0
- package/dist/memory/index.d.ts +3 -0
- package/dist/memory/index.js +3 -0
- package/dist/memory/masking.d.ts +7 -0
- package/dist/memory/masking.js +141 -0
- package/dist/memory/masking.test.d.ts +1 -0
- package/dist/memory/masking.test.js +117 -0
- package/dist/memory/observation.d.ts +38 -0
- package/dist/memory/observation.js +79 -0
- package/dist/memory/rendering/index.d.ts +10 -0
- package/dist/memory/rendering/index.js +13 -0
- package/dist/memory/rendering/renderJsonParts.d.ts +3 -0
- package/dist/memory/rendering/renderJsonParts.js +115 -0
- package/dist/memory/rendering/renderJsonParts.test.d.ts +1 -0
- package/dist/memory/rendering/renderJsonParts.test.js +217 -0
- package/dist/memory/rendering/renderXmlParts.d.ts +7 -0
- package/dist/memory/rendering/renderXmlParts.js +127 -0
- package/dist/memory/serde.d.ts +20 -0
- package/dist/memory/serde.js +81 -0
- package/dist/memory/util.d.ts +2 -0
- package/dist/memory/util.js +17 -0
- package/dist/telemetry/events.d.ts +9 -0
- package/dist/telemetry/events.js +80 -0
- package/dist/telemetry/index.d.ts +6 -0
- package/dist/telemetry/index.js +91 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +1 -0
- package/dist/util.js +12 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +3 -0
- package/dist/web/browserProvider.d.ts +23 -0
- package/dist/web/browserProvider.js +153 -0
- package/dist/web/harness.d.ts +102 -0
- package/dist/web/harness.js +340 -0
- package/dist/web/stability.d.ts +57 -0
- package/dist/web/stability.js +316 -0
- package/dist/web/tabs.d.ts +58 -0
- package/dist/web/tabs.js +293 -0
- package/dist/web/transformer.d.ts +7 -0
- package/dist/web/transformer.js +41 -0
- package/dist/web/types.d.ts +32 -0
- package/dist/web/types.js +2 -0
- package/dist/web/util.d.ts +3 -0
- package/dist/web/util.js +81 -0
- package/dist/web/visualizer/cursor.d.ts +16 -0
- package/dist/web/visualizer/cursor.js +152 -0
- package/dist/web/visualizer/index.d.ts +22 -0
- package/dist/web/visualizer/index.js +47 -0
- package/dist/web/visualizer/mouseEffects.d.ts +18 -0
- package/dist/web/visualizer/mouseEffects.js +287 -0
- package/dist/web/visualizer/typeEffects.d.ts +10 -0
- package/dist/web/visualizer/typeEffects.js +190 -0
- package/package.json +71 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/*************************************************************************************************
|
|
2
|
+
|
|
3
|
+
Welcome to Baml! To use this generated code, please run one of the following:
|
|
4
|
+
|
|
5
|
+
$ npm install @boundaryml/baml
|
|
6
|
+
$ yarn add @boundaryml/baml
|
|
7
|
+
$ pnpm add @boundaryml/baml
|
|
8
|
+
|
|
9
|
+
*************************************************************************************************/
|
|
10
|
+
import { TypeBuilder as _TypeBuilder } from '@boundaryml/baml/type_builder';
|
|
11
|
+
import { DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME } from "./globals";
|
|
12
|
+
export default class TypeBuilder {
|
|
13
|
+
tb;
|
|
14
|
+
AgentContext;
|
|
15
|
+
BugFailureClassification;
|
|
16
|
+
ConnectorInstructions;
|
|
17
|
+
ExtractedData;
|
|
18
|
+
MisalignmentClassification;
|
|
19
|
+
MultiMediaMessage;
|
|
20
|
+
PartialRecipe;
|
|
21
|
+
QueryResponse;
|
|
22
|
+
constructor() {
|
|
23
|
+
this.tb = new _TypeBuilder({
|
|
24
|
+
classes: new Set([
|
|
25
|
+
"AgentContext", "BugFailureClassification", "ConnectorInstructions", "ExtractedData", "MisalignmentClassification", "MultiMediaMessage", "PartialRecipe", "QueryResponse",
|
|
26
|
+
]),
|
|
27
|
+
enums: new Set([]),
|
|
28
|
+
runtime: DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME
|
|
29
|
+
});
|
|
30
|
+
this.AgentContext = this.tb.classViewer("AgentContext", [
|
|
31
|
+
"instructions", "observationContent", "connectorInstructions",
|
|
32
|
+
]);
|
|
33
|
+
this.BugFailureClassification = this.tb.classViewer("BugFailureClassification", [
|
|
34
|
+
"reasoning", "classification", "title", "expectedResult", "actualResult", "severity",
|
|
35
|
+
]);
|
|
36
|
+
this.ConnectorInstructions = this.tb.classViewer("ConnectorInstructions", [
|
|
37
|
+
"connectorId", "instructions",
|
|
38
|
+
]);
|
|
39
|
+
this.ExtractedData = this.tb.classBuilder("ExtractedData", []);
|
|
40
|
+
this.MisalignmentClassification = this.tb.classViewer("MisalignmentClassification", [
|
|
41
|
+
"reasoning", "classification", "fault", "message",
|
|
42
|
+
]);
|
|
43
|
+
this.MultiMediaMessage = this.tb.classViewer("MultiMediaMessage", [
|
|
44
|
+
"role", "cacheControl", "content",
|
|
45
|
+
]);
|
|
46
|
+
this.PartialRecipe = this.tb.classBuilder("PartialRecipe", [
|
|
47
|
+
"reasoning",
|
|
48
|
+
]);
|
|
49
|
+
this.QueryResponse = this.tb.classBuilder("QueryResponse", []);
|
|
50
|
+
}
|
|
51
|
+
__tb() {
|
|
52
|
+
return this.tb._tb();
|
|
53
|
+
}
|
|
54
|
+
string() {
|
|
55
|
+
return this.tb.string();
|
|
56
|
+
}
|
|
57
|
+
literalString(value) {
|
|
58
|
+
return this.tb.literalString(value);
|
|
59
|
+
}
|
|
60
|
+
literalInt(value) {
|
|
61
|
+
return this.tb.literalInt(value);
|
|
62
|
+
}
|
|
63
|
+
literalBool(value) {
|
|
64
|
+
return this.tb.literalBool(value);
|
|
65
|
+
}
|
|
66
|
+
int() {
|
|
67
|
+
return this.tb.int();
|
|
68
|
+
}
|
|
69
|
+
float() {
|
|
70
|
+
return this.tb.float();
|
|
71
|
+
}
|
|
72
|
+
bool() {
|
|
73
|
+
return this.tb.bool();
|
|
74
|
+
}
|
|
75
|
+
list(type) {
|
|
76
|
+
return this.tb.list(type);
|
|
77
|
+
}
|
|
78
|
+
null() {
|
|
79
|
+
return this.tb.null();
|
|
80
|
+
}
|
|
81
|
+
map(key, value) {
|
|
82
|
+
return this.tb.map(key, value);
|
|
83
|
+
}
|
|
84
|
+
union(types) {
|
|
85
|
+
return this.tb.union(types);
|
|
86
|
+
}
|
|
87
|
+
addClass(name) {
|
|
88
|
+
return this.tb.addClass(name);
|
|
89
|
+
}
|
|
90
|
+
addEnum(name) {
|
|
91
|
+
return this.tb.addEnum(name);
|
|
92
|
+
}
|
|
93
|
+
addBaml(baml) {
|
|
94
|
+
this.tb.addBaml(baml);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*************************************************************************************************
|
|
2
|
+
|
|
3
|
+
Welcome to Baml! To use this generated code, please run one of the following:
|
|
4
|
+
|
|
5
|
+
$ npm install @boundaryml/baml
|
|
6
|
+
$ yarn add @boundaryml/baml
|
|
7
|
+
$ pnpm add @boundaryml/baml
|
|
8
|
+
|
|
9
|
+
*************************************************************************************************/
|
|
10
|
+
import type { Image } from "@boundaryml/baml";
|
|
11
|
+
/**
|
|
12
|
+
* Recursively partial type that can be null.
|
|
13
|
+
*
|
|
14
|
+
* @deprecated Use types from the `partial_types` namespace instead, which provides type-safe partial implementations
|
|
15
|
+
* @template T The type to make recursively partial.
|
|
16
|
+
*/
|
|
17
|
+
export type RecursivePartialNull<T> = T extends object ? {
|
|
18
|
+
[P in keyof T]?: RecursivePartialNull<T[P]>;
|
|
19
|
+
} : T | null;
|
|
20
|
+
export interface Checked<T, CheckName extends string = string> {
|
|
21
|
+
value: T;
|
|
22
|
+
checks: Record<CheckName, Check>;
|
|
23
|
+
}
|
|
24
|
+
export interface Check {
|
|
25
|
+
name: string;
|
|
26
|
+
expr: string;
|
|
27
|
+
status: "succeeded" | "failed";
|
|
28
|
+
}
|
|
29
|
+
export declare function all_succeeded<CheckName extends string>(checks: Record<CheckName, Check>): boolean;
|
|
30
|
+
export declare function get_checks<CheckName extends string>(checks: Record<CheckName, Check>): Check[];
|
|
31
|
+
export interface AgentContext {
|
|
32
|
+
instructions?: string | null;
|
|
33
|
+
observationContent: MultiMediaMessage[];
|
|
34
|
+
connectorInstructions: ConnectorInstructions[];
|
|
35
|
+
}
|
|
36
|
+
export interface BugFailureClassification {
|
|
37
|
+
reasoning: string;
|
|
38
|
+
classification: "bug";
|
|
39
|
+
title: string;
|
|
40
|
+
expectedResult: string;
|
|
41
|
+
actualResult: string;
|
|
42
|
+
severity: "critical" | "high" | "medium" | "low";
|
|
43
|
+
}
|
|
44
|
+
export interface ConnectorInstructions {
|
|
45
|
+
connectorId: string;
|
|
46
|
+
instructions: string;
|
|
47
|
+
}
|
|
48
|
+
export interface ExtractedData {
|
|
49
|
+
[key: string]: any;
|
|
50
|
+
}
|
|
51
|
+
export interface MisalignmentClassification {
|
|
52
|
+
reasoning: string;
|
|
53
|
+
classification: "misalignment";
|
|
54
|
+
fault: "test" | "agent";
|
|
55
|
+
message: string;
|
|
56
|
+
}
|
|
57
|
+
export interface MultiMediaMessage {
|
|
58
|
+
role: "user" | "assistant";
|
|
59
|
+
cacheControl: boolean;
|
|
60
|
+
content: (Image | string)[];
|
|
61
|
+
}
|
|
62
|
+
export interface PartialRecipe {
|
|
63
|
+
reasoning: string;
|
|
64
|
+
[key: string]: any;
|
|
65
|
+
}
|
|
66
|
+
export interface QueryResponse {
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
}
|
|
69
|
+
export type MultiMediaContentPart = Image | string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*************************************************************************************************
|
|
2
|
+
|
|
3
|
+
Welcome to Baml! To use this generated code, please run one of the following:
|
|
4
|
+
|
|
5
|
+
$ npm install @boundaryml/baml
|
|
6
|
+
$ yarn add @boundaryml/baml
|
|
7
|
+
$ pnpm add @boundaryml/baml
|
|
8
|
+
|
|
9
|
+
*************************************************************************************************/
|
|
10
|
+
export function all_succeeded(checks) {
|
|
11
|
+
return get_checks(checks).every(check => check.status === "succeeded");
|
|
12
|
+
}
|
|
13
|
+
export function get_checks(checks) {
|
|
14
|
+
return Object.values(checks);
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function completeClaudeCodeAuthFlow(): Promise<string>;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import crypto from 'crypto';
|
|
5
|
+
import { bold, cyanBright } from 'ansis';
|
|
6
|
+
import { exec } from 'node:child_process';
|
|
7
|
+
// Simple cross-platform function to open URLs
|
|
8
|
+
function openUrl(url) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
let command;
|
|
11
|
+
switch (process.platform) {
|
|
12
|
+
case 'darwin':
|
|
13
|
+
command = `open "${url}"`;
|
|
14
|
+
break;
|
|
15
|
+
case 'win32':
|
|
16
|
+
command = `start "${url}"`;
|
|
17
|
+
break;
|
|
18
|
+
default:
|
|
19
|
+
command = `xdg-open "${url}"`;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
exec(command, (error) => {
|
|
23
|
+
if (error) {
|
|
24
|
+
reject(error);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
resolve();
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
// Constants
|
|
33
|
+
const CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
|
|
34
|
+
const CREDS_PATH = join(homedir(), '.magnitude', 'credentials', 'claudeCode.json');
|
|
35
|
+
// 1. Generate PKCE pair
|
|
36
|
+
function generatePKCE() {
|
|
37
|
+
const verifier = crypto.randomBytes(32).toString('base64url');
|
|
38
|
+
const challenge = crypto
|
|
39
|
+
.createHash('sha256')
|
|
40
|
+
.update(verifier)
|
|
41
|
+
.digest('base64url');
|
|
42
|
+
return { verifier, challenge };
|
|
43
|
+
}
|
|
44
|
+
// 2. Get OAuth authorization URL
|
|
45
|
+
function getAuthorizationURL(pkce) {
|
|
46
|
+
const url = new URL('https://claude.ai/oauth/authorize');
|
|
47
|
+
url.searchParams.set('code', 'true');
|
|
48
|
+
url.searchParams.set('client_id', CLIENT_ID);
|
|
49
|
+
url.searchParams.set('response_type', 'code');
|
|
50
|
+
url.searchParams.set('redirect_uri', 'https://console.anthropic.com/oauth/code/callback');
|
|
51
|
+
url.searchParams.set('scope', 'org:create_api_key user:profile user:inference');
|
|
52
|
+
url.searchParams.set('code_challenge', pkce.challenge);
|
|
53
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
54
|
+
url.searchParams.set('state', pkce.verifier);
|
|
55
|
+
return url.toString();
|
|
56
|
+
}
|
|
57
|
+
// 3. Exchange authorization code for tokens
|
|
58
|
+
async function exchangeCodeForTokens(code, verifier) {
|
|
59
|
+
const [authCode, state] = code.split('#');
|
|
60
|
+
const response = await fetch('https://console.anthropic.com/v1/oauth/token', {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { 'Content-Type': 'application/json' },
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
code: authCode,
|
|
65
|
+
state: state,
|
|
66
|
+
grant_type: 'authorization_code',
|
|
67
|
+
client_id: CLIENT_ID,
|
|
68
|
+
redirect_uri: 'https://console.anthropic.com/oauth/code/callback',
|
|
69
|
+
code_verifier: verifier,
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
throw new Error(`Token exchange failed: ${response.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
return {
|
|
77
|
+
access_token: data.access_token,
|
|
78
|
+
refresh_token: data.refresh_token,
|
|
79
|
+
expires_at: Date.now() + (data.expires_in * 1000),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// 4. Refresh access token
|
|
83
|
+
async function refreshAccessToken(refreshToken) {
|
|
84
|
+
const response = await fetch('https://console.anthropic.com/v1/oauth/token', {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers: { 'Content-Type': 'application/json' },
|
|
87
|
+
body: JSON.stringify({
|
|
88
|
+
grant_type: 'refresh_token',
|
|
89
|
+
refresh_token: refreshToken,
|
|
90
|
+
client_id: CLIENT_ID,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`Token refresh failed: ${response.statusText}`);
|
|
95
|
+
}
|
|
96
|
+
const data = await response.json();
|
|
97
|
+
return {
|
|
98
|
+
access_token: data.access_token,
|
|
99
|
+
refresh_token: data.refresh_token,
|
|
100
|
+
expires_at: Date.now() + (data.expires_in * 1000),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// 5. Save credentials
|
|
104
|
+
async function saveCredentials(creds) {
|
|
105
|
+
await fs.mkdir(dirname(CREDS_PATH), { recursive: true });
|
|
106
|
+
await fs.writeFile(CREDS_PATH, JSON.stringify(creds, null, 2));
|
|
107
|
+
await fs.chmod(CREDS_PATH, 0o600); // Read/write for owner only
|
|
108
|
+
}
|
|
109
|
+
// 6. Load credentials
|
|
110
|
+
async function loadCredentials() {
|
|
111
|
+
try {
|
|
112
|
+
const data = await fs.readFile(CREDS_PATH, 'utf-8');
|
|
113
|
+
return JSON.parse(data);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 7. Get valid access token (refresh if needed)
|
|
120
|
+
async function getValidAccessToken() {
|
|
121
|
+
const creds = await loadCredentials();
|
|
122
|
+
if (!creds)
|
|
123
|
+
return null;
|
|
124
|
+
// If token is still valid, return it
|
|
125
|
+
if (creds.expires_at > Date.now() + 60000) { // 1 minute buffer
|
|
126
|
+
return creds.access_token;
|
|
127
|
+
}
|
|
128
|
+
// Otherwise, refresh it
|
|
129
|
+
try {
|
|
130
|
+
const newCreds = await refreshAccessToken(creds.refresh_token);
|
|
131
|
+
await saveCredentials(newCreds);
|
|
132
|
+
return newCreds.access_token;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
export async function completeClaudeCodeAuthFlow() {
|
|
139
|
+
// Try to get existing valid token
|
|
140
|
+
const existingToken = await getValidAccessToken();
|
|
141
|
+
if (existingToken)
|
|
142
|
+
return existingToken;
|
|
143
|
+
// Otherwise, go through auth flow
|
|
144
|
+
const pkce = generatePKCE();
|
|
145
|
+
const authUrl = getAuthorizationURL(pkce);
|
|
146
|
+
console.log(bold `Claude Code Pro/Max access token missing or expired.`);
|
|
147
|
+
//console.log(cyanBright`Accounts with Max plan can be used for API access.`)
|
|
148
|
+
console.log(cyanBright `Opening browser for authentication...`);
|
|
149
|
+
try {
|
|
150
|
+
await openUrl(authUrl);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
console.log('Could not open browser automatically');
|
|
154
|
+
}
|
|
155
|
+
//console.log('Open this URL in your browser:');
|
|
156
|
+
console.log(bold `\nIf browser did not open, visit:`);
|
|
157
|
+
console.log(authUrl);
|
|
158
|
+
console.log(bold `\nPaste the authorization code here:`);
|
|
159
|
+
const code = await new Promise((resolve) => {
|
|
160
|
+
process.stdin.once('data', (data) => {
|
|
161
|
+
resolve(data.toString().trim());
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
const creds = await exchangeCodeForTokens(code, pkce.verifier);
|
|
165
|
+
await saveCredentials(creds);
|
|
166
|
+
console.log(bold `\nCredentials saved!`);
|
|
167
|
+
return creds.access_token;
|
|
168
|
+
}
|
|
169
|
+
/*
|
|
170
|
+
// Usage
|
|
171
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: {
|
|
174
|
+
'Content-Type': 'application/json',
|
|
175
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
176
|
+
'anthropic-beta': 'oauth-2025-04-20',
|
|
177
|
+
// make sure to exclude x-api-key
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify({
|
|
180
|
+
model: 'claude-3-5-sonnet-20241022',
|
|
181
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
182
|
+
max_tokens: 100,
|
|
183
|
+
}),
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
*/
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AgentContext } from "@/ai/baml_client";
|
|
2
|
+
import { Action } from "@/actions/types";
|
|
3
|
+
import { LLMClient, ModelUsage } from "@/ai/types";
|
|
4
|
+
import { ActionDefinition } from "@/actions";
|
|
5
|
+
import { Schema, z } from 'zod';
|
|
6
|
+
import { Image } from '@/memory/image';
|
|
7
|
+
import EventEmitter from "eventemitter3";
|
|
8
|
+
import { MultiMediaContentPart } from "@/memory/rendering";
|
|
9
|
+
interface ModelHarnessOptions {
|
|
10
|
+
llm: LLMClient;
|
|
11
|
+
}
|
|
12
|
+
export interface ModelHarnessEvents {
|
|
13
|
+
'tokensUsed': (usage: ModelUsage) => {};
|
|
14
|
+
}
|
|
15
|
+
export declare class ModelHarness {
|
|
16
|
+
/**
|
|
17
|
+
* Strong reasoning agent for high level strategy and planning.
|
|
18
|
+
*/
|
|
19
|
+
readonly events: EventEmitter<ModelHarnessEvents>;
|
|
20
|
+
private options;
|
|
21
|
+
private collector;
|
|
22
|
+
private cr;
|
|
23
|
+
private baml;
|
|
24
|
+
private logger;
|
|
25
|
+
private prevTotalInputTokens;
|
|
26
|
+
private prevTotalOutputTokens;
|
|
27
|
+
constructor(options: ModelHarnessOptions);
|
|
28
|
+
setup(): Promise<void>;
|
|
29
|
+
describeModel(): string;
|
|
30
|
+
private _reportUsage;
|
|
31
|
+
partialAct<T>(context: AgentContext, // Changed to ModularMemoryContext
|
|
32
|
+
task: string, data: MultiMediaContentPart[], actionVocabulary: ActionDefinition<T>[]): Promise<{
|
|
33
|
+
reasoning: string;
|
|
34
|
+
actions: Action[];
|
|
35
|
+
}>;
|
|
36
|
+
extract<T extends Schema>(instructions: string, schema: T, screenshot: Image, domContent: string): Promise<z.infer<T>>;
|
|
37
|
+
query<T extends Schema>(context: AgentContext, query: string, schema: T): Promise<z.infer<T>>;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { convertToBamlClientOptions } from "./util";
|
|
2
|
+
// Import ModularMemoryContext instead of old MemoryContext
|
|
3
|
+
import { b } from "@/ai/baml_client";
|
|
4
|
+
import { Collector, ClientRegistry } from "@boundaryml/baml";
|
|
5
|
+
import logger from "@/logger";
|
|
6
|
+
import TypeBuilder from "./baml_client/type_builder";
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { convertActionDefinitionsToBaml, convertZodToBaml } from "@/actions/util";
|
|
9
|
+
import EventEmitter from "eventemitter3";
|
|
10
|
+
export class ModelHarness {
|
|
11
|
+
/**
|
|
12
|
+
* Strong reasoning agent for high level strategy and planning.
|
|
13
|
+
*/
|
|
14
|
+
events = new EventEmitter();
|
|
15
|
+
options;
|
|
16
|
+
collector;
|
|
17
|
+
cr;
|
|
18
|
+
baml;
|
|
19
|
+
logger;
|
|
20
|
+
prevTotalInputTokens = 0;
|
|
21
|
+
prevTotalOutputTokens = 0;
|
|
22
|
+
constructor(options) {
|
|
23
|
+
this.options = {
|
|
24
|
+
llm: options.llm,
|
|
25
|
+
//promptCaching: options.promptCaching ?? false
|
|
26
|
+
};
|
|
27
|
+
this.logger = logger.child({ name: 'llm' });
|
|
28
|
+
}
|
|
29
|
+
async setup() {
|
|
30
|
+
// Must be called after constructor
|
|
31
|
+
this.collector = new Collector("macro");
|
|
32
|
+
this.cr = new ClientRegistry();
|
|
33
|
+
let bamlClientOptions = await convertToBamlClientOptions(this.options.llm);
|
|
34
|
+
this.cr.addLlmClient('Magnus', this.options.llm.provider === 'claude-code' ? 'anthropic' : this.options.llm.provider, bamlClientOptions, 'DefaultRetryPolicy');
|
|
35
|
+
this.cr.setPrimary('Magnus');
|
|
36
|
+
this.baml = b.withOptions({ collector: this.collector, clientRegistry: this.cr });
|
|
37
|
+
}
|
|
38
|
+
describeModel() {
|
|
39
|
+
return `${this.options.llm.provider}:${'model' in this.options.llm.options ? this.options.llm.options.model : 'unknown'}`;
|
|
40
|
+
}
|
|
41
|
+
_reportUsage() {
|
|
42
|
+
// console.log('this.collector.last', this.collector.last)
|
|
43
|
+
// if (this.collector.last) console.log("calls:", this.collector.last.calls)//console.log("Response: ", this.collector.last.calls[-1].httpResponse);
|
|
44
|
+
//console.log('last call:', this.collector.last?.calls.at(-1)?.httpResponse?.body.json());
|
|
45
|
+
// Get tokens used since last call to reportUsage
|
|
46
|
+
//console.log(this.collector.usage);
|
|
47
|
+
let inputTokens = 0;
|
|
48
|
+
let outputTokens = 0;
|
|
49
|
+
let cacheWriteInputTokens = 0;
|
|
50
|
+
let cacheReadInputTokens = 0;
|
|
51
|
+
if (this.options.llm.provider === 'anthropic' || this.options.llm.provider === 'claude-code') {
|
|
52
|
+
const usage = this.collector.last?.calls.at(-1)?.httpResponse?.body.json().usage;
|
|
53
|
+
//console.log("Usage from Anthropic:", usage);
|
|
54
|
+
if (!usage) {
|
|
55
|
+
// Sometimes apparently this happens? Happened once after extract for example
|
|
56
|
+
logger.warn("No usage returned from Anthropic provider, cached cost may be inaccurate");
|
|
57
|
+
inputTokens = (this.collector.usage.inputTokens ?? 0) - this.prevTotalInputTokens;
|
|
58
|
+
outputTokens = (this.collector.usage.outputTokens ?? 0) - this.prevTotalOutputTokens;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
inputTokens = usage.input_tokens;
|
|
62
|
+
outputTokens = usage.output_tokens;
|
|
63
|
+
cacheWriteInputTokens = usage.cache_creation_input_tokens;
|
|
64
|
+
cacheReadInputTokens = usage.cache_read_input_tokens;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
inputTokens = (this.collector.usage.inputTokens ?? 0) - this.prevTotalInputTokens;
|
|
69
|
+
outputTokens = (this.collector.usage.outputTokens ?? 0) - this.prevTotalOutputTokens;
|
|
70
|
+
}
|
|
71
|
+
const model = this.options.llm.options.model ?? 'unknown';
|
|
72
|
+
// Get cost if known
|
|
73
|
+
const knownCostMap = {
|
|
74
|
+
// TODO: track cached savings on Gemini
|
|
75
|
+
'gemini-2.5-pro': { inputTokens: 1.25, outputTokens: 10.0 },
|
|
76
|
+
'gemini-2.5-flash': { inputTokens: 0.30, outputTokens: 2.50 },
|
|
77
|
+
'gemini-2.5-flash-lite': { inputTokens: 0.10, outputTokens: 0.40 },
|
|
78
|
+
'claude-3.5-sonnet': { inputTokens: 3.00, outputTokens: 15.00, cacheWriteInputTokens: 3.75, cacheReadInputTokens: 0.30 },
|
|
79
|
+
'claude-3.7-sonnet': { inputTokens: 3.00, outputTokens: 15.00, cacheWriteInputTokens: 3.75, cacheReadInputTokens: 0.30 },
|
|
80
|
+
'claude-sonnet-4': { inputTokens: 3.00, outputTokens: 15.00, cacheWriteInputTokens: 3.75, cacheReadInputTokens: 0.30 },
|
|
81
|
+
'claude-haiku-4-5': { inputTokens: 1.00, outputTokens: 5.00, cacheWriteInputTokens: 1.25, cacheReadInputTokens: 0.10 },
|
|
82
|
+
'claude-opus-4': { inputTokens: 15.00, outputTokens: 75.00, cacheWriteInputTokens: 18.75, cacheReadInputTokens: 1.50 },
|
|
83
|
+
'gpt-4.1': { inputTokens: 2.00, outputTokens: 8.00 },
|
|
84
|
+
'gpt-4.1-mini': { inputTokens: 0.40, outputTokens: 1.60 },
|
|
85
|
+
'gpt-4.1-nano': { inputTokens: 0.10, outputTokens: 0.40 },
|
|
86
|
+
'gpt-4o': { inputTokens: 3.75, outputTokens: 15.00 },
|
|
87
|
+
// Assuming Nebius prices, may be higher
|
|
88
|
+
'qwen2.5-vl-72b': { inputTokens: 0.25, outputTokens: 0.75 }
|
|
89
|
+
};
|
|
90
|
+
let inputTokenCost;
|
|
91
|
+
let outputTokenCost;
|
|
92
|
+
let cacheWriteInputTokenCost;
|
|
93
|
+
let cacheReadInputTokenCost;
|
|
94
|
+
for (const [name, costs] of Object.entries(knownCostMap)) {
|
|
95
|
+
if (model.includes(name)) {
|
|
96
|
+
inputTokenCost = costs.inputTokens / 1_000_000;
|
|
97
|
+
outputTokenCost = costs.outputTokens / 1_000_000;
|
|
98
|
+
cacheReadInputTokenCost = costs.cacheReadInputTokens ? costs.cacheReadInputTokens / 1_000_000 : undefined;
|
|
99
|
+
cacheWriteInputTokenCost = costs.cacheWriteInputTokens ? costs.cacheWriteInputTokens / 1_000_000 : undefined;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// console.log("cacheWriteInputTokenCost:", cacheWriteInputTokenCost);
|
|
103
|
+
// console.log("cacheWriteInputTokens:", cacheWriteInputTokens);
|
|
104
|
+
const usage = {
|
|
105
|
+
llm: {
|
|
106
|
+
provider: this.options.llm.provider,
|
|
107
|
+
model: model
|
|
108
|
+
}, //this.options.llm,
|
|
109
|
+
inputTokens: inputTokens,
|
|
110
|
+
outputTokens: outputTokens,
|
|
111
|
+
...(cacheWriteInputTokens ? { cacheWriteInputTokens } : {}),
|
|
112
|
+
...(cacheReadInputTokens ? { cacheReadInputTokens } : {}),
|
|
113
|
+
...(inputTokenCost ? {
|
|
114
|
+
inputCost: inputTokens * inputTokenCost +
|
|
115
|
+
(cacheWriteInputTokenCost ? cacheWriteInputTokenCost * cacheWriteInputTokens : 0.0) +
|
|
116
|
+
(cacheReadInputTokenCost ? cacheReadInputTokenCost * cacheReadInputTokens : 0.0)
|
|
117
|
+
} : {}),
|
|
118
|
+
...(outputTokenCost ? { outputCost: outputTokens * outputTokenCost } : {}),
|
|
119
|
+
// ...(cacheWriteInputTokenCost ? { : inputTokens * inputTokenCost } : {}),
|
|
120
|
+
// ...(cacheReadInputTokenCost ? { outputCost: outputTokens * outputTokenCost } : {})
|
|
121
|
+
};
|
|
122
|
+
this.events.emit('tokensUsed', usage);
|
|
123
|
+
//console.log("Usage:", usage);
|
|
124
|
+
this.prevTotalInputTokens += inputTokens;
|
|
125
|
+
this.prevTotalOutputTokens += outputTokens;
|
|
126
|
+
}
|
|
127
|
+
async partialAct(context, // Changed to ModularMemoryContext
|
|
128
|
+
task, data, actionVocabulary) {
|
|
129
|
+
const tb = new TypeBuilder();
|
|
130
|
+
tb.PartialRecipe.addProperty('actions', tb.list(convertActionDefinitionsToBaml(tb, actionVocabulary))).description('Always provide at least one action');
|
|
131
|
+
const start = Date.now();
|
|
132
|
+
// Assuming this.baml.CreatePartialRecipe is now typed to accept ModularMemoryContext
|
|
133
|
+
// after BAML generation picked up changes in planner.baml
|
|
134
|
+
const response = await this.baml.CreatePartialRecipe(context, task, data, this.options.llm.provider === 'claude-code', { tb });
|
|
135
|
+
this.logger.trace(`createPartialRecipe took ${Date.now() - start}ms`);
|
|
136
|
+
// BAML does not carry over action type to @@dynamic of PartialRecipe, so forced cast necssary
|
|
137
|
+
//return response as unknown as { actions: z.infer<ActionDefinition<T>['schema']>[] };//, finished: boolean };
|
|
138
|
+
this._reportUsage();
|
|
139
|
+
return {
|
|
140
|
+
reasoning: response.reasoning, //(response.observations ? response.observations + " " : "") + response.meta_reasoning + " " + response.reasoning,
|
|
141
|
+
actions: response.actions // as z.infer<ActionDefinition<T>['schema']>[]
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async extract(instructions, schema, screenshot, domContent) {
|
|
145
|
+
const tb = new TypeBuilder();
|
|
146
|
+
if (schema instanceof z.ZodObject) {
|
|
147
|
+
// populate ExtractedData with schema KVs instead of wrapping in data key unnecessarily
|
|
148
|
+
for (const [key, fieldSchema] of Object.entries(schema.shape)) {
|
|
149
|
+
tb.ExtractedData.addProperty(key, convertZodToBaml(tb, fieldSchema));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// for array or primitive have to wrap data key
|
|
154
|
+
tb.ExtractedData.addProperty('data', convertZodToBaml(tb, schema));
|
|
155
|
+
}
|
|
156
|
+
// } else if (schema instanceof z.ZodArray) {
|
|
157
|
+
// }
|
|
158
|
+
const resp = await this.baml.ExtractData(instructions, await screenshot.toBaml(), domContent, this.options.llm.provider === 'claude-code', { tb });
|
|
159
|
+
this._reportUsage();
|
|
160
|
+
if (schema instanceof z.ZodObject) {
|
|
161
|
+
return resp;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
return resp.data;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// ^ extract could prob be a subset of query w trimmed mem
|
|
168
|
+
async query(context, query, schema) {
|
|
169
|
+
const tb = new TypeBuilder();
|
|
170
|
+
if (schema instanceof z.ZodObject) {
|
|
171
|
+
// populate ExtractedData with schema KVs instead of wrapping in data key unnecessarily
|
|
172
|
+
for (const [key, fieldSchema] of Object.entries(schema.shape)) {
|
|
173
|
+
tb.QueryResponse.addProperty(key, convertZodToBaml(tb, fieldSchema));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// for array or primitive have to wrap data key
|
|
178
|
+
tb.QueryResponse.addProperty('data', convertZodToBaml(tb, schema));
|
|
179
|
+
}
|
|
180
|
+
const resp = await this.baml.QueryMemory(context, query, this.options.llm.provider === 'claude-code', { tb });
|
|
181
|
+
this._reportUsage();
|
|
182
|
+
if (schema instanceof z.ZodObject) {
|
|
183
|
+
return resp;
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
return resp.data;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { MultiMediaContentPart } from "@/memory/rendering";
|
|
2
|
+
import { ModelHarnessEvents } from "./modelHarness";
|
|
3
|
+
import { LLMClient } from "./types";
|
|
4
|
+
import { ActionDefinition } from "@/actions";
|
|
5
|
+
import { AgentContext } from "./baml_client";
|
|
6
|
+
import { Action } from "@/actions/types";
|
|
7
|
+
import { Image } from '@/memory/image';
|
|
8
|
+
import EventEmitter from "eventemitter3";
|
|
9
|
+
import z from "zod";
|
|
10
|
+
export declare class MultiModelHarness {
|
|
11
|
+
/**
|
|
12
|
+
* Delegates model responsibilites to different LLMs and consolidates their usage
|
|
13
|
+
*/
|
|
14
|
+
private roles;
|
|
15
|
+
private uniqueModels;
|
|
16
|
+
readonly events: EventEmitter<ModelHarnessEvents>;
|
|
17
|
+
constructor(clients: LLMClient[]);
|
|
18
|
+
setup(): Promise<void>;
|
|
19
|
+
describe(): string;
|
|
20
|
+
partialAct<T>(context: AgentContext, task: string, data: MultiMediaContentPart[], actionVocabulary: ActionDefinition<T>[]): Promise<{
|
|
21
|
+
reasoning: string;
|
|
22
|
+
actions: Action[];
|
|
23
|
+
}>;
|
|
24
|
+
extract<T extends z.Schema>(instructions: string, schema: T, screenshot: Image, domContent: string): Promise<z.infer<T>>;
|
|
25
|
+
query<T extends z.Schema>(context: AgentContext, query: string, schema: T): Promise<z.infer<T>>;
|
|
26
|
+
get numUniqueModels(): number;
|
|
27
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ModelHarness } from "./modelHarness";
|
|
2
|
+
import { allBrowserAgentRoles } from "./types";
|
|
3
|
+
import EventEmitter from "eventemitter3";
|
|
4
|
+
export class MultiModelHarness {
|
|
5
|
+
/**
|
|
6
|
+
* Delegates model responsibilites to different LLMs and consolidates their usage
|
|
7
|
+
*/
|
|
8
|
+
// Roles may reference the same harness
|
|
9
|
+
roles = {};
|
|
10
|
+
uniqueModels = [];
|
|
11
|
+
events = new EventEmitter();
|
|
12
|
+
constructor(clients) {
|
|
13
|
+
// Sort by specificity (from least specific to most specific)
|
|
14
|
+
const sortedClients = clients.toSorted((a, b) => (b.roles ? b.roles.length : 9999) - (a.roles ? a.roles.length : 9999));
|
|
15
|
+
for (const client of sortedClients) {
|
|
16
|
+
const harness = new ModelHarness({ llm: client });
|
|
17
|
+
this.uniqueModels.push(harness);
|
|
18
|
+
if (client.roles) {
|
|
19
|
+
for (const role of client.roles) {
|
|
20
|
+
this.roles[role] = harness;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
for (const role of allBrowserAgentRoles) {
|
|
25
|
+
this.roles[role] = harness;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Forward token usage events upward
|
|
29
|
+
harness.events.on('tokensUsed', (usage) => { this.events.emit('tokensUsed', usage); }, this);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async setup() {
|
|
33
|
+
await Promise.all(this.uniqueModels.map(model => model.setup()));
|
|
34
|
+
}
|
|
35
|
+
describe() {
|
|
36
|
+
// for now - describe least specific model
|
|
37
|
+
return this.uniqueModels[0].describeModel();
|
|
38
|
+
}
|
|
39
|
+
// TODO: generalize responsibility delegation
|
|
40
|
+
async partialAct(context, task, data, actionVocabulary) {
|
|
41
|
+
return await this.roles['act'].partialAct(context, task, data, actionVocabulary);
|
|
42
|
+
}
|
|
43
|
+
async extract(instructions, schema, screenshot, domContent) {
|
|
44
|
+
return await this.roles['extract'].extract(instructions, schema, screenshot, domContent);
|
|
45
|
+
}
|
|
46
|
+
async query(context, query, schema) {
|
|
47
|
+
return await this.roles['query'].query(context, query, schema);
|
|
48
|
+
}
|
|
49
|
+
get numUniqueModels() {
|
|
50
|
+
return this.uniqueModels.length;
|
|
51
|
+
}
|
|
52
|
+
}
|