@agenthifive/openclaw 0.1.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.
Files changed (65) hide show
  1. package/README.md +124 -0
  2. package/dist/client.d.ts +27 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +136 -0
  5. package/dist/client.js.map +1 -0
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +23 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/jwt-utils.d.ts +29 -0
  11. package/dist/jwt-utils.d.ts.map +1 -0
  12. package/dist/jwt-utils.js +55 -0
  13. package/dist/jwt-utils.js.map +1 -0
  14. package/dist/patch-verify.d.ts +28 -0
  15. package/dist/patch-verify.d.ts.map +1 -0
  16. package/dist/patch-verify.js +72 -0
  17. package/dist/patch-verify.js.map +1 -0
  18. package/dist/pending-approvals.d.ts +55 -0
  19. package/dist/pending-approvals.d.ts.map +1 -0
  20. package/dist/pending-approvals.js +95 -0
  21. package/dist/pending-approvals.js.map +1 -0
  22. package/dist/prompt-reference.d.ts +51 -0
  23. package/dist/prompt-reference.d.ts.map +1 -0
  24. package/dist/prompt-reference.js +645 -0
  25. package/dist/prompt-reference.js.map +1 -0
  26. package/dist/register.d.ts +20 -0
  27. package/dist/register.d.ts.map +1 -0
  28. package/dist/register.js +551 -0
  29. package/dist/register.js.map +1 -0
  30. package/dist/runtime.d.ts +66 -0
  31. package/dist/runtime.d.ts.map +1 -0
  32. package/dist/runtime.js +87 -0
  33. package/dist/runtime.js.map +1 -0
  34. package/dist/session-context.d.ts +39 -0
  35. package/dist/session-context.d.ts.map +1 -0
  36. package/dist/session-context.js +58 -0
  37. package/dist/session-context.js.map +1 -0
  38. package/dist/setup-wizard.d.ts +28 -0
  39. package/dist/setup-wizard.d.ts.map +1 -0
  40. package/dist/setup-wizard.js +303 -0
  41. package/dist/setup-wizard.js.map +1 -0
  42. package/dist/tools.d.ts +27 -0
  43. package/dist/tools.d.ts.map +1 -0
  44. package/dist/tools.js +128 -0
  45. package/dist/tools.js.map +1 -0
  46. package/dist/types.d.ts +93 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +2 -0
  49. package/dist/types.js.map +1 -0
  50. package/dist/vault-action-proxy.d.ts +75 -0
  51. package/dist/vault-action-proxy.d.ts.map +1 -0
  52. package/dist/vault-action-proxy.js +152 -0
  53. package/dist/vault-action-proxy.js.map +1 -0
  54. package/dist/vault-provider.d.ts +52 -0
  55. package/dist/vault-provider.d.ts.map +1 -0
  56. package/dist/vault-provider.js +37 -0
  57. package/dist/vault-provider.js.map +1 -0
  58. package/dist/vault-token-manager.d.ts +42 -0
  59. package/dist/vault-token-manager.d.ts.map +1 -0
  60. package/dist/vault-token-manager.js +124 -0
  61. package/dist/vault-token-manager.js.map +1 -0
  62. package/openclaw.plugin.json +59 -0
  63. package/package.json +58 -0
  64. package/patches/README.md +85 -0
  65. package/patches/model-auth.patch +44 -0
@@ -0,0 +1,124 @@
1
+ import { importES256Key, exchangeToken } from "./jwt-utils.js";
2
+ export class VaultTokenManager {
3
+ baseUrl;
4
+ agentId;
5
+ privateKeyJWK;
6
+ tokenAudience;
7
+ privateKeyObj = null;
8
+ accessToken = null;
9
+ tokenExpiresAt = 0; // epoch ms
10
+ refreshTimer = null;
11
+ refreshInFlight = null;
12
+ /** Called after every successful token refresh with the new token. */
13
+ onRefresh = null;
14
+ /** Called when token refresh fails with 401 — indicates the agent's key is no longer valid. */
15
+ onAuthFailure = null;
16
+ constructor(config) {
17
+ this.baseUrl = config.baseUrl.replace(/\/+$/, "");
18
+ this.agentId = config.agentId;
19
+ this.privateKeyJWK = config.privateKey;
20
+ this.tokenAudience = (config.tokenAudience ?? this.baseUrl).replace(/\/+$/, "");
21
+ }
22
+ /**
23
+ * Perform the initial token exchange and start the background refresh timer.
24
+ * Must be called (and awaited) before getToken().
25
+ */
26
+ async init() {
27
+ // Import the JWK once
28
+ this.privateKeyObj = await importES256Key(this.privateKeyJWK);
29
+ // Initial token exchange
30
+ await this.refreshToken();
31
+ // Schedule background refresh — check every 30s, refresh when near expiry
32
+ this.refreshTimer = setInterval(() => {
33
+ if (Date.now() >= this.tokenExpiresAt - 60_000) {
34
+ this.refreshToken().catch((err) => {
35
+ const ttlLeft = Math.max(0, Math.round((this.tokenExpiresAt - Date.now()) / 1000));
36
+ console.error(`[vault-token-manager] refresh failed (current token expires in ${ttlLeft}s, ` +
37
+ `prefix: ${this.accessToken?.slice(0, 4) ?? "none"}): ${err instanceof Error ? err.message : String(err)}`);
38
+ });
39
+ }
40
+ }, 30_000);
41
+ // Don't keep the process alive just for token refresh
42
+ if (this.refreshTimer &&
43
+ typeof this.refreshTimer === "object" &&
44
+ "unref" in this.refreshTimer) {
45
+ this.refreshTimer.unref();
46
+ }
47
+ }
48
+ /**
49
+ * Get the current bearer token. Synchronous — relies on background refresh.
50
+ * Throws if init() hasn't been called.
51
+ */
52
+ getToken() {
53
+ if (!this.accessToken) {
54
+ throw new Error("VaultTokenManager not initialized — call init() first");
55
+ }
56
+ return this.accessToken;
57
+ }
58
+ /** Stop the background refresh timer. */
59
+ stop() {
60
+ if (this.refreshTimer) {
61
+ clearInterval(this.refreshTimer);
62
+ this.refreshTimer = null;
63
+ }
64
+ }
65
+ /**
66
+ * Force an immediate token refresh. Called on-demand when a 401 is received.
67
+ * Coalesces concurrent requests — if a refresh is already in flight, callers
68
+ * wait for the same promise instead of hammering the token endpoint.
69
+ */
70
+ async forceRefresh() {
71
+ if (this.refreshInFlight) {
72
+ try {
73
+ await this.refreshInFlight;
74
+ return true;
75
+ }
76
+ catch {
77
+ return false;
78
+ }
79
+ }
80
+ const attempt = this.refreshToken();
81
+ this.refreshInFlight = attempt;
82
+ try {
83
+ await attempt;
84
+ return true;
85
+ }
86
+ catch {
87
+ return false;
88
+ }
89
+ finally {
90
+ this.refreshInFlight = null;
91
+ }
92
+ }
93
+ async refreshToken() {
94
+ if (!this.privateKeyObj) {
95
+ throw new Error("Private key not imported — call init() first");
96
+ }
97
+ try {
98
+ const result = await exchangeToken(this.privateKeyObj, {
99
+ baseUrl: this.baseUrl,
100
+ agentId: this.agentId,
101
+ tokenAudience: this.tokenAudience,
102
+ });
103
+ const previousToken = this.accessToken;
104
+ this.accessToken = result.accessToken;
105
+ this.tokenExpiresAt = Date.now() + result.expiresIn * 1000;
106
+ console.log(`[vault-token-manager] Token refreshed (prefix: ${this.accessToken.slice(0, 4)}..., ` +
107
+ `ttl: ${result.expiresIn}s, previous: ${previousToken ? previousToken.slice(0, 4) + "..." : "none"})`);
108
+ // Notify listener (register.ts uses this to update the shared mutable auth object)
109
+ this.onRefresh?.(this.accessToken);
110
+ }
111
+ catch (err) {
112
+ // Check for 401 specifically
113
+ if (err instanceof Error && err.message.includes("401")) {
114
+ console.error("[vault-token-manager] Token exchange rejected (401). " +
115
+ "The agent's key pair is no longer valid — agent may have been disabled or key rotated. " +
116
+ "Generate a bootstrap secret from the AgentHiFive dashboard (Agents → Bootstrap Secret), " +
117
+ "then run `openclaw configure` to reconnect.");
118
+ this.onAuthFailure?.();
119
+ }
120
+ throw err;
121
+ }
122
+ }
123
+ }
124
+ //# sourceMappingURL=vault-token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-token-manager.js","sourceRoot":"","sources":["../src/vault-token-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ {
2
+ "id": "agenthifive",
3
+ "name": "AgentHiFive Vault",
4
+ "description": "Vault-managed credentials, brokered API proxy, and policy-governed access for AI agents",
5
+ "version": "0.1.0",
6
+ "configSchema": {
7
+ "type": "object",
8
+ "properties": {
9
+ "baseUrl": {
10
+ "type": "string",
11
+ "description": "AgentHiFive Vault API base URL",
12
+ "default": "https://app.agenthifive.com"
13
+ },
14
+ "auth": {
15
+ "type": "object",
16
+ "properties": {
17
+ "mode": {
18
+ "type": "string",
19
+ "enum": ["bearer", "agent"],
20
+ "description": "Authentication mode: 'bearer' for opaque token, 'agent' for ES256 JWT"
21
+ },
22
+ "token": {
23
+ "type": "string",
24
+ "description": "Bearer token (only for mode=bearer)"
25
+ },
26
+ "agentId": {
27
+ "type": "string",
28
+ "description": "Agent ID (only for mode=agent)"
29
+ },
30
+ "privateKey": {
31
+ "type": "string",
32
+ "description": "ES256 private key as base64-encoded JWK (only for mode=agent)"
33
+ },
34
+ "tokenAudience": {
35
+ "type": "string",
36
+ "description": "Token audience override (optional, defaults to baseUrl)"
37
+ }
38
+ },
39
+ "required": ["mode"]
40
+ },
41
+ "pollTimeoutMs": {
42
+ "type": "number",
43
+ "description": "Approval polling timeout in milliseconds (default: 300000 = 5 min)",
44
+ "default": 300000
45
+ },
46
+ "pollIntervalMs": {
47
+ "type": "number",
48
+ "description": "Approval polling interval in milliseconds (default: 3000 = 3s)",
49
+ "default": 3000
50
+ },
51
+ "connectedProviders": {
52
+ "type": "array",
53
+ "items": { "type": "string" },
54
+ "description": "List of connected provider names for prompt injection (e.g., ['google', 'microsoft', 'notion'])"
55
+ }
56
+ },
57
+ "required": ["auth"]
58
+ }
59
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@agenthifive/openclaw",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./runtime": {
13
+ "types": "./dist/runtime.d.ts",
14
+ "default": "./dist/runtime.js"
15
+ }
16
+ },
17
+ "openclaw": {
18
+ "extensions": ["./dist/register.js"]
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "openclaw.plugin.json",
23
+ "patches"
24
+ ],
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "typecheck": "tsc -p tsconfig.json --noEmit",
28
+ "test": "tsc -p tsconfig.json && node --experimental-transform-types --test src/__tests__/*.test.ts",
29
+ "lint": "echo Lint: OK"
30
+ },
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/supersantux/AgentH5.git",
35
+ "directory": "packages/openclaw"
36
+ },
37
+ "homepage": "https://github.com/supersantux/AgentH5/tree/main/packages/openclaw#readme",
38
+ "keywords": [
39
+ "openclaw",
40
+ "agenthifive",
41
+ "vault",
42
+ "ai-agent",
43
+ "credential-management",
44
+ "oauth",
45
+ "policy-engine",
46
+ "plugin"
47
+ ],
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "dependencies": {
52
+ "jose": "^5.9.3"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^20.0.0",
56
+ "typescript": "^5.6.0"
57
+ }
58
+ }
@@ -0,0 +1,85 @@
1
+ # AgentHiFive OpenClaw Patches
2
+
3
+ Optional patches that enable credential proxying features in OpenClaw core.
4
+
5
+ **These patches are NOT required for basic functionality.** The AgentHiFive plugin
6
+ works fully without patches — tools, prompt injection, approval flow, and the
7
+ brokered API proxy (Model B) all work out of the box. Patches only enable
8
+ **LLM credential proxying** (routing LLM API calls through the vault).
9
+
10
+ ## Available Patches
11
+
12
+ ### `model-auth.patch`
13
+
14
+ Adds vault credential resolution to OpenClaw's `resolveApiKeyForProvider()` function
15
+ in `src/agents/model-auth.ts`. This inserts two new resolution tiers before the
16
+ existing local profile lookup:
17
+
18
+ | Tier | What it does | When it activates |
19
+ |------|-------------|-------------------|
20
+ | **Tier 0** | Returns the vault bearer token directly | Provider is in `proxiedProviders` list |
21
+ | **Tier 0.5** | Queries the vault credential provider chain | Always (falls through if no credentials found) |
22
+
23
+ The patch uses `await import("@agenthifive/openclaw/runtime")` wrapped in try/catch,
24
+ so it's a **complete no-op** when the plugin is not installed — safe for vanilla OpenClaw.
25
+
26
+ ## How to Apply
27
+
28
+ ### Using pnpm patch (recommended)
29
+
30
+ ```bash
31
+ # 1. Start the patch session
32
+ pnpm patch openclaw
33
+
34
+ # 2. Apply the patch to the extracted directory
35
+ # (pnpm will print the temporary directory path)
36
+ cd <temp-directory>
37
+ patch -p1 < /path/to/@agenthifive/openclaw/patches/model-auth.patch
38
+
39
+ # 3. Commit the patch
40
+ pnpm patch-commit <temp-directory>
41
+ ```
42
+
43
+ This adds a `patchedDependencies` entry to your `package.json` that pnpm applies
44
+ automatically on `pnpm install`.
45
+
46
+ ### Manual application
47
+
48
+ ```bash
49
+ cd /path/to/openclaw
50
+ patch -p1 < node_modules/@agenthifive/openclaw/patches/model-auth.patch
51
+ ```
52
+
53
+ Note: Manual patches are lost on `npm install` / `pnpm install`. Use `pnpm patch`
54
+ for persistence.
55
+
56
+ ## Verification
57
+
58
+ After applying, the AgentHiFive plugin will log at startup:
59
+
60
+ ```
61
+ AgentHiFive: model-auth patch detected — credential proxying enabled
62
+ ```
63
+
64
+ Without the patch, you'll see:
65
+
66
+ ```
67
+ AgentHiFive: model-auth patch not detected. LLM credential proxying is unavailable.
68
+ ```
69
+
70
+ ## Compatibility
71
+
72
+ | OpenClaw Version | Patch Status |
73
+ |-----------------|-------------|
74
+ | Latest (Mar 2026) | Compatible |
75
+
76
+ The patch targets `resolveApiKeyForProvider()` in `src/agents/model-auth.ts`.
77
+ If OpenClaw restructures this function significantly, the patch may need
78
+ regeneration. Check the [AgentHiFive releases](https://github.com/supersantux/AgentH5/releases)
79
+ for updated patches.
80
+
81
+ ## When Patches Become Unnecessary
82
+
83
+ When OpenClaw merges support for `apiKeyOverride` in the `before_model_resolve`
84
+ hook result type, the plugin can use the hook API directly and patches will be
85
+ deprecated. Track progress in the upstream PR.
@@ -0,0 +1,44 @@
1
+ --- a/src/agents/model-auth.ts
2
+ +++ b/src/agents/model-auth.ts
3
+ @@ -289,7 +289,41 @@
4
+ }): Promise<ResolvedProviderAuth> {
5
+ const { provider, cfg, profileId, preferredProfile } = params;
6
+ const store = params.store ?? ensureAuthProfileStore(params.agentDir);
7
+
8
+ + // -- Tier 0: AgentHiFive proxied providers (vault bearer token) --
9
+ + // When the provider is in proxiedProviders, the vault acts as an LLM proxy.
10
+ + // Return the managed vault bearer token directly -- no local API key needed.
11
+ + // @agenthifive/openclaw/runtime -- dynamic import is a no-op when plugin is not installed.
12
+ + try {
13
+ + const runtime = await import("@agenthifive/openclaw/runtime");
14
+ + if (runtime.isInitialized()) {
15
+ + const proxiedProviders = runtime.getProxiedProviders();
16
+ + if (proxiedProviders.includes(provider)) {
17
+ + const vaultToken = runtime.getVaultBearerToken();
18
+ + if (vaultToken) {
19
+ + return { apiKey: vaultToken, source: "vault:agent-token", mode: "api-key" };
20
+ + }
21
+ + }
22
+ +
23
+ + // -- Tier 0.5: Credential provider chain --
24
+ + // Try the vault credential provider before local profiles.
25
+ + const vaultResult = await runtime.resolveCredential({
26
+ + kind: "model_provider",
27
+ + provider,
28
+ + profileId: preferredProfile,
29
+ + });
30
+ + if (vaultResult?.apiKey) {
31
+ + return {
32
+ + apiKey: vaultResult.apiKey,
33
+ + source: "credential-provider:vault",
34
+ + mode: vaultResult.mode ?? "api-key",
35
+ + };
36
+ + }
37
+ + }
38
+ + } catch {
39
+ + // Plugin not installed -- skip vault credential resolution
40
+ + }
41
+ +
42
+ if (profileId) {
43
+ const resolved = await resolveApiKeyForProfile({
44
+ cfg,