@tokensmind/agent-network 0.1.0 → 0.1.3
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 +81 -7
- package/openclaw.plugin.json +2 -2
- package/package.json +18 -8
- package/skills/tokensmind-agent-network/SKILL.md +145 -0
- package/skills/tokensmind-agent-network/package.json +4 -0
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/action_support.py +3 -1
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/agent_network_runtime.py +61 -9
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/action-executor.js +12 -1
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/action-validation.js +5 -0
- package/skills/tokensmind-agent-network/scripts/lib/agent-actions.js +91 -0
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/api-client.js +14 -2
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/contact-action.js +1 -1
- package/skills/tokensmind-agent-network/scripts/lib/memory-actions.js +112 -0
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/connector.js +8 -19
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/credentialStore.js +60 -11
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/requestPolicy.js +0 -11
- package/skills/tokensmind-agent-network/scripts/lib/runtime/systemCredentialStore.js +245 -0
- package/skills/tokensmind-agent-network/scripts/lib/runtime/systemCredentialSupport.js +71 -0
- package/skills/tokensmind-agent-network/scripts/memory_actions.py +131 -0
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/connector.py +8 -8
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/credential_store.py +56 -12
- package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/request_policy.py +1 -13
- package/skills/tokensmind-agent-network/scripts/python_runtime/system_credential_store.py +250 -0
- package/src/action-executor.js +12 -1
- package/src/action-validation.js +5 -0
- package/src/agent-actions.js +53 -6
- package/src/api-client.js +14 -2
- package/src/contact-action.js +1 -1
- package/src/index.js +4 -2
- package/src/memory-actions.js +112 -0
- package/src/runtime/connector.js +8 -19
- package/src/runtime/credentialStore.js +60 -11
- package/src/runtime/requestPolicy.js +0 -11
- package/src/runtime/systemCredentialStore.js +143 -74
- package/src/runtime/systemCredentialSupport.js +71 -0
- package/skills/tokensmind-agent-network-runtime/SKILL.md +0 -55
- package/skills/tokensmind-agent-network-runtime/scripts/lib/agent-actions.js +0 -44
- package/skills/tokensmind-agent-network-runtime/scripts/lib/runtime/systemCredentialStore.js +0 -176
- package/skills/tokensmind-agent-network-runtime/scripts/python_runtime/system_credential_store.py +0 -143
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/action_executor.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/action_validation.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/agent-network-runtime.mjs +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/governance_actions.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/action-context.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/action-errors.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/governance-actions.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/messaging-actions.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/browser.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/constants.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/crypto.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/deviceAuthorization.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/httpClient.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/runtime/portableStore.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/lib/workflow-store.js +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/__init__.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/browser.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/constants.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/crypto.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/device_authorization.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/errors.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/http_client.py +0 -0
- /package/skills/{tokensmind-agent-network-runtime → tokensmind-agent-network}/scripts/python_runtime/portable_store.py +0 -0
package/src/agent-actions.js
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { actionFailure, requireInput } from './action-errors.js';
|
|
2
|
-
import {
|
|
2
|
+
import { text } from './action-validation.js';
|
|
3
|
+
|
|
4
|
+
function profileTags(value) {
|
|
5
|
+
if (value === undefined || value === null) return [];
|
|
6
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
7
|
+
requireInput(['agent.tags'], 'agent.tags must be an array of strings.');
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
3
11
|
|
|
4
12
|
export async function searchAgents(context) {
|
|
5
13
|
const query = text(context.input.query);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
if (!query) requireInput(['query']);
|
|
15
|
+
try {
|
|
16
|
+
return await context.get(`/agent-network-api/agents?q=${encodeURIComponent(query)}`);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
const code = error?.code;
|
|
19
|
+
if (!['AGENT_REQUIRED', 'AGENT_PROFILE_REQUIRED'].includes(code)) throw error;
|
|
20
|
+
actionFailure(
|
|
21
|
+
code,
|
|
22
|
+
'Create the account Agent profile with ensure_agent before searching.',
|
|
23
|
+
{ nextOperation: 'ensure_agent' },
|
|
24
|
+
);
|
|
25
|
+
}
|
|
10
26
|
}
|
|
11
27
|
|
|
12
28
|
export async function getMyAgent(context) {
|
|
@@ -25,7 +41,21 @@ function profileInput(input) {
|
|
|
25
41
|
const name = text(profile.name);
|
|
26
42
|
const description = text(profile.description);
|
|
27
43
|
if (!name || !description) requireInput(['agent.name', 'agent.description']);
|
|
28
|
-
return { name, description };
|
|
44
|
+
return { name, description, tags: profileTags(profile.tags) };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function profileUpdateInput(input, existing) {
|
|
48
|
+
const profile = input.agent || input.profile || {};
|
|
49
|
+
const hasName = Object.hasOwn(profile, 'name');
|
|
50
|
+
const hasDescription = Object.hasOwn(profile, 'description');
|
|
51
|
+
const hasTags = Object.hasOwn(profile, 'tags');
|
|
52
|
+
if (!hasName && !hasDescription && !hasTags) {
|
|
53
|
+
requireInput(['agent.name', 'agent.description', 'agent.tags']);
|
|
54
|
+
}
|
|
55
|
+
const name = text(hasName ? profile.name : existing.name);
|
|
56
|
+
const description = text(hasDescription ? profile.description : existing.description);
|
|
57
|
+
if (!name || !description) requireInput(['agent.name', 'agent.description']);
|
|
58
|
+
return { name, description, tags: profileTags(hasTags ? profile.tags : existing.tags) };
|
|
29
59
|
}
|
|
30
60
|
|
|
31
61
|
export async function ensureAgent(context) {
|
|
@@ -42,3 +72,20 @@ export async function ensureAgent(context) {
|
|
|
42
72
|
}
|
|
43
73
|
return { agent: result.agent, created: true };
|
|
44
74
|
}
|
|
75
|
+
|
|
76
|
+
export async function updateAgent(context) {
|
|
77
|
+
const existing = await getMyAgent(context);
|
|
78
|
+
if (!existing) {
|
|
79
|
+
actionFailure('AGENT_PROFILE_REQUIRED', 'Create the account Agent profile before updating it.');
|
|
80
|
+
}
|
|
81
|
+
const result = await context.mutate({
|
|
82
|
+
method: 'PATCH',
|
|
83
|
+
path: `/agent-network-api/agents/${encodeURIComponent(existing.id)}`,
|
|
84
|
+
body: profileUpdateInput(context.input, existing),
|
|
85
|
+
label: 'agent:update',
|
|
86
|
+
});
|
|
87
|
+
if (!result?.agent) {
|
|
88
|
+
actionFailure('AGENT_UPDATE_PROTOCOL_ERROR', 'Agent update returned no Agent.');
|
|
89
|
+
}
|
|
90
|
+
return { agent: result.agent, updated: true };
|
|
91
|
+
}
|
package/src/api-client.js
CHANGED
|
@@ -12,7 +12,7 @@ const CLIENT_VERSION = '0.1.0';
|
|
|
12
12
|
|
|
13
13
|
export class AuthorizationRequiredError extends Error {
|
|
14
14
|
constructor(verificationUrl) {
|
|
15
|
-
super('
|
|
15
|
+
super('Default browser handoff failed; resume the pending action to continue polling.');
|
|
16
16
|
this.name = 'AuthorizationRequiredError';
|
|
17
17
|
this.status = 'authorization_required';
|
|
18
18
|
this.verificationUrl = verificationUrl;
|
|
@@ -54,7 +54,19 @@ export function createActionApi(options = {}) {
|
|
|
54
54
|
baseUrl, stateDir, platform, env, homeDir, hostname, browser, http, store, writeEvent,
|
|
55
55
|
} = resolveOptions(options);
|
|
56
56
|
const origin = normalizeBaseUrl(baseUrl);
|
|
57
|
-
const resolvedStore = store || createCredentialStore({
|
|
57
|
+
const resolvedStore = store || createCredentialStore({
|
|
58
|
+
stateDir,
|
|
59
|
+
origin,
|
|
60
|
+
platform,
|
|
61
|
+
env,
|
|
62
|
+
homeDir,
|
|
63
|
+
onFallback: ({ backend, directory, reason }) => writeEvent({
|
|
64
|
+
event: 'credential_store_fallback',
|
|
65
|
+
backend,
|
|
66
|
+
directory,
|
|
67
|
+
reason,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
58
70
|
const workflowStore = createWorkflowStore({ stateDir, origin, platform, homeDir });
|
|
59
71
|
const connector = createConnector({
|
|
60
72
|
baseUrl: origin,
|
package/src/contact-action.js
CHANGED
|
@@ -19,7 +19,7 @@ async function resolveTarget(context) {
|
|
|
19
19
|
const name = text(target.name);
|
|
20
20
|
if (!name) requireInput(['target.id or target.name']);
|
|
21
21
|
const agents = await context.get(
|
|
22
|
-
`/agent-network-api/agents?q=${encodeURIComponent(name)}
|
|
22
|
+
`/agent-network-api/agents?q=${encodeURIComponent(name)}`,
|
|
23
23
|
);
|
|
24
24
|
if (!Array.isArray(agents) || agents.length === 0) {
|
|
25
25
|
actionFailure('TARGET_AGENT_NOT_FOUND', `No Agent matched "${name}".`);
|
package/src/index.js
CHANGED
|
@@ -12,9 +12,11 @@ const ACTION_SCHEMA = {
|
|
|
12
12
|
operation: {
|
|
13
13
|
type: 'string',
|
|
14
14
|
enum: [
|
|
15
|
-
'abandon_action', 'search_agents', 'get_my_agent', 'ensure_agent', '
|
|
15
|
+
'abandon_action', 'search_agents', 'get_my_agent', 'ensure_agent', 'update_agent',
|
|
16
|
+
'contact_agent',
|
|
16
17
|
'list_inbox', 'get_conversation', 'reply', 'mark_read',
|
|
17
18
|
'withdraw_message', 'block_agent', 'unblock_agent', 'report', 'appeal',
|
|
19
|
+
'get_memory_settings', 'propose_memory', 'list_memories', 'delete_memory',
|
|
18
20
|
],
|
|
19
21
|
},
|
|
20
22
|
input: {
|
|
@@ -57,7 +59,7 @@ function getExecutor(config) {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export default defineToolPlugin({
|
|
60
|
-
id: 'tokensmind-agent-network
|
|
62
|
+
id: 'tokensmind-agent-network',
|
|
61
63
|
name: 'TokensMind Agent Network Runtime',
|
|
62
64
|
description: 'Run high-level Agent Network operations with private authorization.',
|
|
63
65
|
configSchema: CONFIG_SCHEMA,
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { actionFailure, requireInput } from './action-errors.js';
|
|
2
|
+
import { getMyAgent } from './agent-actions.js';
|
|
3
|
+
import { isObject, optionalLimit, requiredId, requiredText, text } from './action-validation.js';
|
|
4
|
+
|
|
5
|
+
const MEMORY_KINDS = new Set(['agent_experience', 'matching_preference']);
|
|
6
|
+
const MEMORY_POLARITIES = new Set(['negative', 'positive']);
|
|
7
|
+
const MEMORY_SCOPES = new Set(['contextual', 'global']);
|
|
8
|
+
// platform_event 由服务端独占写入,客户端提交会被拒绝。
|
|
9
|
+
const MEMORY_SOURCES = new Set(['model_inferred', 'user_explicit']);
|
|
10
|
+
const MEMORY_STATUSES = new Set(['active', 'deleted', 'pending_review', 'rejected']);
|
|
11
|
+
const MAX_INFERRED_CONFIDENCE = 0.6;
|
|
12
|
+
|
|
13
|
+
function requireChoice(input, field, allowed) {
|
|
14
|
+
const value = text(input?.[field]).toLowerCase();
|
|
15
|
+
if (!allowed.has(value)) requireInput([field], `${field} has an unsupported value.`);
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function optionalConfidence(value, sourceType) {
|
|
20
|
+
if (value === undefined || value === null || value === '') {
|
|
21
|
+
return sourceType === 'model_inferred' ? MAX_INFERRED_CONFIDENCE : 1;
|
|
22
|
+
}
|
|
23
|
+
const confidence = Number(value);
|
|
24
|
+
const inferredLimitExceeded = sourceType === 'model_inferred'
|
|
25
|
+
&& confidence > MAX_INFERRED_CONFIDENCE;
|
|
26
|
+
if (!Number.isFinite(confidence) || confidence <= 0 || confidence > 1 || inferredLimitExceeded) {
|
|
27
|
+
requireInput(['confidence'], 'confidence must be above 0 and no more than 0.6 for inferred memory.');
|
|
28
|
+
}
|
|
29
|
+
return confidence;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function ownedAgent(context) {
|
|
33
|
+
const agent = await getMyAgent(context);
|
|
34
|
+
if (!agent) actionFailure('AGENT_PROFILE_REQUIRED', 'Create the account Agent profile first.');
|
|
35
|
+
return agent;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function agentPath(agentId, suffix) {
|
|
39
|
+
return `/agent-network-api/agents/${encodeURIComponent(agentId)}/${suffix}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function optionalText(input, field) {
|
|
43
|
+
return Object.hasOwn(input, field) ? text(input[field]) || null : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function memoryBody(input) {
|
|
47
|
+
if (!isObject(input)) requireInput(['input']);
|
|
48
|
+
const sourceType = requireChoice(input, 'sourceType', MEMORY_SOURCES);
|
|
49
|
+
const scope = input.scope ? requireChoice(input, 'scope', MEMORY_SCOPES) : 'contextual';
|
|
50
|
+
const contextText = scope === 'global' ? '' : requiredText(input, 'contextText');
|
|
51
|
+
return {
|
|
52
|
+
clientMemoryId: requiredText(input, 'clientMemoryId'),
|
|
53
|
+
confidence: optionalConfidence(input.confidence, sourceType),
|
|
54
|
+
contextText,
|
|
55
|
+
conversationId: optionalText(input, 'conversationId'),
|
|
56
|
+
expiresAt: optionalText(input, 'expiresAt'),
|
|
57
|
+
kind: requireChoice(input, 'kind', MEMORY_KINDS),
|
|
58
|
+
polarity: requireChoice(input, 'polarity', MEMORY_POLARITIES),
|
|
59
|
+
requirementId: optionalText(input, 'requirementId'),
|
|
60
|
+
scope,
|
|
61
|
+
sourceType,
|
|
62
|
+
statement: requiredText(input, 'statement'),
|
|
63
|
+
targetAgentId: optionalText(input, 'targetAgentId'),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function listQuery(input) {
|
|
68
|
+
const params = new URLSearchParams({ limit: String(optionalLimit(input.limit)) });
|
|
69
|
+
if (input.offset !== undefined) {
|
|
70
|
+
const offset = Number(input.offset);
|
|
71
|
+
if (!Number.isInteger(offset) || offset < 0) requireInput(['offset']);
|
|
72
|
+
params.set('offset', String(offset));
|
|
73
|
+
}
|
|
74
|
+
if (input.status) params.set('status', requireChoice(input, 'status', MEMORY_STATUSES));
|
|
75
|
+
return params.toString();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function getMemorySettings(context) {
|
|
79
|
+
const agent = await ownedAgent(context);
|
|
80
|
+
return context.get(agentPath(agent.id, 'memory-settings'));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function proposeMemory(context) {
|
|
84
|
+
const body = memoryBody(context.input);
|
|
85
|
+
const agent = await ownedAgent(context);
|
|
86
|
+
const settings = await context.get(agentPath(agent.id, 'memory-settings'));
|
|
87
|
+
if (settings?.collectionEnabled !== true) {
|
|
88
|
+
actionFailure('MEMORY_COLLECTION_DISABLED', 'Memory collection is disabled for this Agent.');
|
|
89
|
+
}
|
|
90
|
+
return context.mutate({
|
|
91
|
+
method: 'POST',
|
|
92
|
+
path: agentPath(agent.id, 'memories'),
|
|
93
|
+
body,
|
|
94
|
+
label: 'memory:propose',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export async function listMemories(context) {
|
|
99
|
+
const query = listQuery(context.input);
|
|
100
|
+
const agent = await ownedAgent(context);
|
|
101
|
+
return context.get(`${agentPath(agent.id, 'memories')}?${query}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function deleteMemory(context) {
|
|
105
|
+
const memoryId = requiredId(context.input, 'memoryId');
|
|
106
|
+
const agent = await ownedAgent(context);
|
|
107
|
+
return context.mutate({
|
|
108
|
+
method: 'DELETE',
|
|
109
|
+
path: `${agentPath(agent.id, 'memories')}/${encodeURIComponent(memoryId)}`,
|
|
110
|
+
label: 'memory:delete',
|
|
111
|
+
});
|
|
112
|
+
}
|
package/src/runtime/connector.js
CHANGED
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
} from './deviceAuthorization.js';
|
|
9
9
|
import {
|
|
10
10
|
buildBusinessUrl,
|
|
11
|
-
isPublicDiscoveryRequest,
|
|
12
11
|
validateBusinessRequest,
|
|
13
12
|
} from './requestPolicy.js';
|
|
14
13
|
|
|
@@ -47,15 +46,6 @@ function assertActiveCredential(active) {
|
|
|
47
46
|
return active;
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
function authorizationPending(verificationUrl) {
|
|
51
|
-
const error = new Error(
|
|
52
|
-
'Complete Agent Network authorization in the browser, then retry the action.',
|
|
53
|
-
);
|
|
54
|
-
error.status = 'authorization_required';
|
|
55
|
-
error.verificationUrl = verificationUrl;
|
|
56
|
-
return error;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
49
|
async function executeBusinessRequest({ operation, token, baseUrl, http, signal }) {
|
|
60
50
|
return http.request({
|
|
61
51
|
url: buildBusinessUrl(baseUrl, operation.path),
|
|
@@ -90,7 +80,6 @@ async function authorize({ operation, store, browser, baseUrl, http, client, sig
|
|
|
90
80
|
pending = await createRemoteAuthorization({ pending, baseUrl, http, client, signal });
|
|
91
81
|
await store.write('pending', pending);
|
|
92
82
|
await browser.open(pending.authorization.verificationUrl);
|
|
93
|
-
throw authorizationPending(pending.authorization.verificationUrl);
|
|
94
83
|
}
|
|
95
84
|
if (pending.phase === 'authorizing') {
|
|
96
85
|
await waitForApproval({ pending, baseUrl, http, signal });
|
|
@@ -131,6 +120,11 @@ function isInvalidAgentCredential(error) {
|
|
|
131
120
|
].includes(error.code);
|
|
132
121
|
}
|
|
133
122
|
|
|
123
|
+
function requiresAuthorization(error) {
|
|
124
|
+
return error instanceof AgentNetworkHttpError
|
|
125
|
+
&& (error.status === 401 || isInvalidAgentCredential(error));
|
|
126
|
+
}
|
|
127
|
+
|
|
134
128
|
async function executeAndFinalize({ pending, active, dependencies }) {
|
|
135
129
|
assertActiveCredential(active);
|
|
136
130
|
try {
|
|
@@ -144,7 +138,7 @@ async function executeAndFinalize({ pending, active, dependencies }) {
|
|
|
144
138
|
} catch (error) {
|
|
145
139
|
if (error instanceof AgentNetworkHttpError && error.status < 500 && error.status !== 429) {
|
|
146
140
|
await dependencies.store.remove('pending');
|
|
147
|
-
if (
|
|
141
|
+
if (requiresAuthorization(error)) await dependencies.store.remove('active');
|
|
148
142
|
}
|
|
149
143
|
throw error;
|
|
150
144
|
}
|
|
@@ -170,7 +164,7 @@ export function createConnector({ store, browser, baseUrl, http, client }) {
|
|
|
170
164
|
try {
|
|
171
165
|
return await executeBusinessRequest({ operation, token: active.token, baseUrl, http, signal });
|
|
172
166
|
} catch (error) {
|
|
173
|
-
if (!
|
|
167
|
+
if (!requiresAuthorization(error)) throw error;
|
|
174
168
|
await store.remove('active');
|
|
175
169
|
return authorizeAndExecute(operation, signal);
|
|
176
170
|
}
|
|
@@ -181,15 +175,10 @@ export function createConnector({ store, browser, baseUrl, http, client }) {
|
|
|
181
175
|
const normalized = validateBusinessRequest(params);
|
|
182
176
|
const operation = { ...normalized, body: params.body };
|
|
183
177
|
const reauthorize = params.reauthorize === true;
|
|
178
|
+
|
|
184
179
|
const pending = await store.read('pending');
|
|
185
180
|
const active = await store.read('active');
|
|
186
|
-
|
|
187
181
|
if (pending) return resumePending(pending, operation, signal);
|
|
188
|
-
|
|
189
|
-
if (isPublicDiscoveryRequest(operation) && !reauthorize) {
|
|
190
|
-
return executeBusinessRequest({ operation, baseUrl, http, signal });
|
|
191
|
-
}
|
|
192
|
-
|
|
193
182
|
if (!active || reauthorize) return authorizeAndExecute(operation, signal);
|
|
194
183
|
return executeWithActive(operation, active, signal);
|
|
195
184
|
}
|
|
@@ -6,7 +6,10 @@ import {
|
|
|
6
6
|
originNamespace,
|
|
7
7
|
resolvePortableStateDir,
|
|
8
8
|
} from './portableStore.js';
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
resolveSystemCredentialStore,
|
|
11
|
+
SystemCredentialStoreError,
|
|
12
|
+
} from './systemCredentialStore.js';
|
|
10
13
|
|
|
11
14
|
const RECORD_NAMES = Object.freeze(['instance', 'pending', 'active']);
|
|
12
15
|
|
|
@@ -122,6 +125,53 @@ function createFileStores({ directories, origin, platform, env, homeDir, fs, ran
|
|
|
122
125
|
}));
|
|
123
126
|
}
|
|
124
127
|
|
|
128
|
+
async function validateSystemRecords(systemStore) {
|
|
129
|
+
for (const name of RECORD_NAMES) await systemStore.read(name);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function initializeStore({
|
|
133
|
+
systemStore, fallback, fallbackDirectory, legacyDirectories, storeOptions, onFallback,
|
|
134
|
+
}) {
|
|
135
|
+
const recordDirectory = path.join(
|
|
136
|
+
fallbackDirectory, originNamespace(storeOptions.origin),
|
|
137
|
+
);
|
|
138
|
+
const legacySources = createFileStores({
|
|
139
|
+
...storeOptions, directories: legacyDirectories,
|
|
140
|
+
});
|
|
141
|
+
if (!systemStore) {
|
|
142
|
+
onFallback({
|
|
143
|
+
backend: null,
|
|
144
|
+
directory: recordDirectory,
|
|
145
|
+
reason: 'No supported system credential store is available',
|
|
146
|
+
});
|
|
147
|
+
await migrateCredentialStores({ target: fallback, sources: legacySources });
|
|
148
|
+
return fallback;
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
if (typeof systemStore.verifyAvailability !== 'function') {
|
|
152
|
+
throw new SystemCredentialStoreError(
|
|
153
|
+
'System credential store does not support availability verification',
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
await systemStore.verifyAvailability();
|
|
157
|
+
await validateSystemRecords(systemStore);
|
|
158
|
+
const sources = createFileStores({
|
|
159
|
+
...storeOptions, directories: [fallbackDirectory, ...legacyDirectories],
|
|
160
|
+
});
|
|
161
|
+
await migrateCredentialStores({ target: systemStore, sources });
|
|
162
|
+
return systemStore;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
if (!(error instanceof SystemCredentialStoreError)) throw error;
|
|
165
|
+
onFallback({
|
|
166
|
+
backend: systemStore.backend,
|
|
167
|
+
directory: recordDirectory,
|
|
168
|
+
reason: error.message,
|
|
169
|
+
});
|
|
170
|
+
await migrateCredentialStores({ target: fallback, sources: legacySources });
|
|
171
|
+
return fallback;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
125
175
|
export function createCredentialStore({
|
|
126
176
|
stateDir,
|
|
127
177
|
origin,
|
|
@@ -133,6 +183,7 @@ export function createCredentialStore({
|
|
|
133
183
|
secureStore,
|
|
134
184
|
resolveSecureStore = resolveSystemCredentialStore,
|
|
135
185
|
run,
|
|
186
|
+
onFallback = () => {},
|
|
136
187
|
} = {}) {
|
|
137
188
|
if (stateDir) {
|
|
138
189
|
return createPortableStore({ stateDir, origin, platform, env, homeDir, fs, randomId });
|
|
@@ -147,16 +198,14 @@ export function createCredentialStore({
|
|
|
147
198
|
platform, namespace: originNamespace(origin), env, fs, run,
|
|
148
199
|
})
|
|
149
200
|
: secureStore;
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
201
|
+
const legacyDirectories = resolveLegacyStateDirs({ platform, env, homeDir });
|
|
202
|
+
return initializeStore({
|
|
203
|
+
systemStore,
|
|
204
|
+
fallback,
|
|
205
|
+
fallbackDirectory,
|
|
206
|
+
legacyDirectories: [...new Set(legacyDirectories)],
|
|
207
|
+
storeOptions: { origin, platform, env, homeDir, fs, randomId },
|
|
208
|
+
onFallback,
|
|
158
209
|
});
|
|
159
|
-
await migrateCredentialStores({ target, sources });
|
|
160
|
-
return target;
|
|
161
210
|
});
|
|
162
211
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { INTERNAL_PATH_PATTERNS, MUTATION_METHODS } from './constants.js';
|
|
2
2
|
|
|
3
3
|
const SUPPORTED_METHODS = new Set(['GET', 'POST', 'PATCH', 'DELETE']);
|
|
4
|
-
const PUBLIC_AGENT_DIRECTORY_PATH = '/agent-network-api/agents';
|
|
5
|
-
|
|
6
4
|
export function normalizeBaseUrl(value) {
|
|
7
5
|
const url = new URL(value);
|
|
8
6
|
if (!['http:', 'https:'].includes(url.protocol)) {
|
|
@@ -44,12 +42,3 @@ export function buildBusinessUrl(baseUrl, path) {
|
|
|
44
42
|
}
|
|
45
43
|
return url.toString();
|
|
46
44
|
}
|
|
47
|
-
|
|
48
|
-
export function isPublicDiscoveryRequest({ method, path }) {
|
|
49
|
-
if (method !== 'GET') return false;
|
|
50
|
-
const url = new URL(path, 'https://tokensmind.invalid');
|
|
51
|
-
const mineRequested = [...url.searchParams.entries()]
|
|
52
|
-
.some(([key, value]) => key === 'mine' && value === '1');
|
|
53
|
-
return url.pathname === PUBLIC_AGENT_DIRECTORY_PATH
|
|
54
|
-
&& !mineRequested;
|
|
55
|
-
}
|