totemlayer 0.1.24 → 0.1.29
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 +40 -32
- package/bin/agent-runner.mjs +1 -0
- package/bin/agent-setup.mjs +12 -3
- package/bin/automatic-runtime.mjs +63 -5
- package/bin/connected-agent-service.mjs +5 -1
- package/bin/device-login.mjs +8 -1
- package/bin/installation.mjs +50 -6
- package/bin/mcp.mjs +236 -45
- package/bin/network-runtime.mjs +19 -6
- package/bin/sdk/action-types.js +0 -1
- package/bin/sdk/actions.js +1 -84
- package/bin/sdk/errors.js +1 -67
- package/bin/sdk/index.d.ts +36 -1
- package/bin/sdk/index.js +1 -431
- package/bin/sdk/inspector.js +1 -323
- package/bin/sdk/request-options.js +1 -36
- package/bin/sdk/transport.js +1 -202
- package/bin/sdk/types.d.ts +58 -1
- package/bin/sdk/types.js +0 -1
- package/bin/totem.mjs +2 -2
- package/package.json +1 -1
- package/scripts/prepare.mjs +16 -1
package/bin/sdk/actions.js
CHANGED
|
@@ -1,84 +1 @@
|
|
|
1
|
-
import { TotemError } from "
|
|
2
|
-
import { requireActionChecksKey, signalOnlyOptions } from "./request-options.js";
|
|
3
|
-
import { Transport } from "./transport.js";
|
|
4
|
-
export * from "./action-types.js";
|
|
5
|
-
function responseField(payload, key) {
|
|
6
|
-
const value = payload[key];
|
|
7
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
8
|
-
throw new TotemError("Totem returned an invalid Action Checks response.", {
|
|
9
|
-
code: "INVALID_RESPONSE",
|
|
10
|
-
});
|
|
11
|
-
}
|
|
12
|
-
return value;
|
|
13
|
-
}
|
|
14
|
-
function proposal(action) {
|
|
15
|
-
const authorityFields = [
|
|
16
|
-
"organizationId",
|
|
17
|
-
"userId",
|
|
18
|
-
"ownerUserId",
|
|
19
|
-
"requestedByUserId",
|
|
20
|
-
"requestedByApiKeyId",
|
|
21
|
-
"principal",
|
|
22
|
-
"authentication",
|
|
23
|
-
"apiKeyId",
|
|
24
|
-
"from",
|
|
25
|
-
];
|
|
26
|
-
if (!action || typeof action !== "object" || authorityFields.some((key) => key in action)) {
|
|
27
|
-
throw new TotemError("Action Checks caller authority comes from its separate scoped API key.", {
|
|
28
|
-
code: "INVALID_ACTION",
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return action;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Separately authenticated Action Checks client. Human approval stays in Totem's UI.
|
|
35
|
-
* Writes are never automatically replayed, even when the action has an idempotency key.
|
|
36
|
-
* After an ambiguous execution failure, use get() to inspect the receipt before proceeding.
|
|
37
|
-
*/
|
|
38
|
-
export class TotemActions {
|
|
39
|
-
#transport;
|
|
40
|
-
constructor(options) {
|
|
41
|
-
this.#transport = new Transport({
|
|
42
|
-
apiKey: requireActionChecksKey(options.actionChecksApiKey),
|
|
43
|
-
baseUrl: options.baseUrl,
|
|
44
|
-
timeoutMs: options.timeoutMs,
|
|
45
|
-
maxRetries: options.maxRetries,
|
|
46
|
-
retryDelayMs: options.retryDelayMs,
|
|
47
|
-
fetch: options.fetch,
|
|
48
|
-
}, { basePath: "/api/action-checks", responseEnvelope: "object" });
|
|
49
|
-
}
|
|
50
|
-
async create(action, options) {
|
|
51
|
-
const result = await this.#transport.request("POST", "", {
|
|
52
|
-
...signalOnlyOptions(options),
|
|
53
|
-
body: { action: proposal(action) },
|
|
54
|
-
});
|
|
55
|
-
return responseField(result, "suite");
|
|
56
|
-
}
|
|
57
|
-
async get(suiteId, options) {
|
|
58
|
-
const result = await this.#transport.request("GET", `/${encodeURIComponent(suiteId)}`, signalOnlyOptions(options));
|
|
59
|
-
return responseField(result, "suite");
|
|
60
|
-
}
|
|
61
|
-
async issueGrant(suiteId, action, options) {
|
|
62
|
-
const result = await this.#transport.request("POST", `/${encodeURIComponent(suiteId)}/grant`, {
|
|
63
|
-
...signalOnlyOptions(options),
|
|
64
|
-
body: { action: proposal(action) },
|
|
65
|
-
});
|
|
66
|
-
return responseField(result, "grant");
|
|
67
|
-
}
|
|
68
|
-
async execute(suiteId, input, options) {
|
|
69
|
-
const result = await this.#transport.request("POST", `/${encodeURIComponent(suiteId)}/execute`, {
|
|
70
|
-
...signalOnlyOptions(options),
|
|
71
|
-
body: { action: proposal(input.action), grant: input.grant },
|
|
72
|
-
});
|
|
73
|
-
const suite = responseField(result, "suite");
|
|
74
|
-
const receipt = result.receipt === null
|
|
75
|
-
? null
|
|
76
|
-
: responseField(result, "receipt");
|
|
77
|
-
if (typeof result.receiptId !== "string" || !result.receiptId) {
|
|
78
|
-
throw new TotemError("Totem returned an invalid execution receipt ID.", {
|
|
79
|
-
code: "INVALID_RESPONSE",
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
return { suite, receipt, receiptId: result.receiptId };
|
|
83
|
-
}
|
|
84
|
-
}
|
|
1
|
+
import{TotemError}from"./errors.js";import{requireActionChecksKey,signalOnlyOptions}from"./request-options.js";import{Transport}from"./transport.js";export*from"./action-types.js";function responseField(payload,key){const value=payload[key];if(!value||typeof value!=="object"||Array.isArray(value)){throw new TotemError("Totem returned an invalid Action Checks response.",{code:"INVALID_RESPONSE"})}return value}function proposal(action){const authorityFields=["organizationId","userId","ownerUserId","requestedByUserId","requestedByApiKeyId","principal","authentication","apiKeyId","from"];if(!action||typeof action!=="object"||authorityFields.some(key=>key in action)){throw new TotemError("Action Checks caller authority comes from its separate scoped API key.",{code:"INVALID_ACTION"})}return action}class TotemActions{#transport;constructor(options){this.#transport=new Transport({apiKey:requireActionChecksKey(options.actionChecksApiKey),baseUrl:options.baseUrl,timeoutMs:options.timeoutMs,maxRetries:options.maxRetries,retryDelayMs:options.retryDelayMs,fetch:options.fetch},{basePath:"/api/action-checks",responseEnvelope:"object"})}async create(action,options){const result=await this.#transport.request("POST","",{...signalOnlyOptions(options),body:{action:proposal(action)}});return responseField(result,"suite")}async get(suiteId,options){const result=await this.#transport.request("GET",`/${encodeURIComponent(suiteId)}`,signalOnlyOptions(options));return responseField(result,"suite")}async issueGrant(suiteId,action,options){const result=await this.#transport.request("POST",`/${encodeURIComponent(suiteId)}/grant`,{...signalOnlyOptions(options),body:{action:proposal(action)}});return responseField(result,"grant")}async execute(suiteId,input,options){const result=await this.#transport.request("POST",`/${encodeURIComponent(suiteId)}/execute`,{...signalOnlyOptions(options),body:{action:proposal(input.action),grant:input.grant}});const suite=responseField(result,"suite");const receipt=result.receipt===null?null:responseField(result,"receipt");if(typeof result.receiptId!=="string"||!result.receiptId){throw new TotemError("Totem returned an invalid execution receipt ID.",{code:"INVALID_RESPONSE"})}return{suite,receipt,receiptId:result.receiptId}}}export{TotemActions};
|
package/bin/sdk/errors.js
CHANGED
|
@@ -1,67 +1 @@
|
|
|
1
|
-
|
|
2
|
-
code;
|
|
3
|
-
status;
|
|
4
|
-
requestId;
|
|
5
|
-
retryAfterSeconds;
|
|
6
|
-
constructor(message, options) {
|
|
7
|
-
super(message, { cause: options.cause });
|
|
8
|
-
this.name = new.target.name;
|
|
9
|
-
this.code = options.code;
|
|
10
|
-
this.status = options.status;
|
|
11
|
-
this.requestId = options.requestId;
|
|
12
|
-
this.retryAfterSeconds = options.retryAfterSeconds;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
export class TotemAuthenticationError extends TotemError {
|
|
16
|
-
}
|
|
17
|
-
export class TotemPermissionError extends TotemError {
|
|
18
|
-
}
|
|
19
|
-
export class TotemNotFoundError extends TotemError {
|
|
20
|
-
}
|
|
21
|
-
export class TotemConflictError extends TotemError {
|
|
22
|
-
}
|
|
23
|
-
export class TotemRateLimitError extends TotemError {
|
|
24
|
-
}
|
|
25
|
-
export class TotemTimeoutError extends TotemError {
|
|
26
|
-
}
|
|
27
|
-
export class TotemNetworkError extends TotemError {
|
|
28
|
-
}
|
|
29
|
-
export class TotemCanceledError extends TotemError {
|
|
30
|
-
}
|
|
31
|
-
export function apiError(status, body, requestId) {
|
|
32
|
-
const error = body &&
|
|
33
|
-
typeof body === "object" &&
|
|
34
|
-
"error" in body &&
|
|
35
|
-
body.error &&
|
|
36
|
-
typeof body.error === "object"
|
|
37
|
-
? body.error
|
|
38
|
-
: {};
|
|
39
|
-
const message = "message" in error && typeof error.message === "string"
|
|
40
|
-
? error.message
|
|
41
|
-
: `Totem request failed (${status}).`;
|
|
42
|
-
const code = "code" in error && typeof error.code === "string" ? error.code : "HTTP_ERROR";
|
|
43
|
-
const id = "requestId" in error && typeof error.requestId === "string" ? error.requestId : requestId;
|
|
44
|
-
const Constructor = status === 401
|
|
45
|
-
? TotemAuthenticationError
|
|
46
|
-
: status === 403
|
|
47
|
-
? TotemPermissionError
|
|
48
|
-
: status === 404
|
|
49
|
-
? TotemNotFoundError
|
|
50
|
-
: status === 409
|
|
51
|
-
? TotemConflictError
|
|
52
|
-
: status === 429
|
|
53
|
-
? TotemRateLimitError
|
|
54
|
-
: TotemError;
|
|
55
|
-
const details = "details" in error ? error.details : undefined;
|
|
56
|
-
const retryAfter = details && typeof details === "object" && "retryAfterSeconds" in details
|
|
57
|
-
? details.retryAfterSeconds
|
|
58
|
-
: undefined;
|
|
59
|
-
const retryAfterSeconds = status === 429 &&
|
|
60
|
-
typeof retryAfter === "number" &&
|
|
61
|
-
Number.isSafeInteger(retryAfter) &&
|
|
62
|
-
retryAfter > 0 &&
|
|
63
|
-
retryAfter <= 86400
|
|
64
|
-
? retryAfter
|
|
65
|
-
: undefined;
|
|
66
|
-
return new Constructor(message, { code, status, requestId: id, retryAfterSeconds });
|
|
67
|
-
}
|
|
1
|
+
class TotemError extends Error{code;status;requestId;retryAfterSeconds;constructor(message,options){super(message,{cause:options.cause});this.name=new.target.name;this.code=options.code;this.status=options.status;this.requestId=options.requestId;this.retryAfterSeconds=options.retryAfterSeconds}}class TotemAuthenticationError extends TotemError{}class TotemPermissionError extends TotemError{}class TotemNotFoundError extends TotemError{}class TotemConflictError extends TotemError{}class TotemRateLimitError extends TotemError{}class TotemTimeoutError extends TotemError{}class TotemNetworkError extends TotemError{}class TotemCanceledError extends TotemError{}function apiError(status,body,requestId){const error=body&&typeof body==="object"&&"error"in body&&body.error&&typeof body.error==="object"?body.error:{};const message="message"in error&&typeof error.message==="string"?error.message:`Totem request failed (${status}).`;const code="code"in error&&typeof error.code==="string"?error.code:"HTTP_ERROR";const id="requestId"in error&&typeof error.requestId==="string"?error.requestId:requestId;const Constructor=status===401?TotemAuthenticationError:status===403?TotemPermissionError:status===404?TotemNotFoundError:status===409?TotemConflictError:status===429?TotemRateLimitError:TotemError;const details="details"in error?error.details:void 0;const retryAfter=details&&typeof details==="object"&&"retryAfterSeconds"in details?details.retryAfterSeconds:void 0;const retryAfterSeconds=status===429&&typeof retryAfter==="number"&&Number.isSafeInteger(retryAfter)&&retryAfter>0&&retryAfter<=86400?retryAfter:void 0;return new Constructor(message,{code,status,requestId:id,retryAfterSeconds})}export{TotemAuthenticationError,TotemCanceledError,TotemConflictError,TotemError,TotemNetworkError,TotemNotFoundError,TotemPermissionError,TotemRateLimitError,TotemTimeoutError,apiError};
|
package/bin/sdk/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createLocalInspector, InspectionError } from "./inspector.js";
|
|
2
2
|
import type { ActionProposal, AssistantActionCheck, AssistantActionCheckList, AssistantActionReceiptResult, AssistantCheckOptions } from "./action-types.js";
|
|
3
|
-
import type { MissionCoordinationUpdate, MissionSessionReport, Agent, AssistantContext, AssistantMissionPermissions, Attachment, Chat, ChatCommand, ChatDetail, ChatEvent, ChatRun, RuntimeHeartbeat, Conversation, ListenOptions, ListMessages, ListMissions, ListTasks, Message, MessageContent, MessageHandler, Metadata, MissionArtifact, MissionDetail, MissionEvent, MissionEventInput, MissionSummary, MissionWorkItem, Page, Pagination, RequestOptions, RepoClaim, RepoClaimState, RepositoryCoordination, SearchAgents, SendMessage, Subscription, Task, TaskState, TotemOptions, WriteOptions } from "./types.js";
|
|
3
|
+
import type { MissionCoordinationUpdate, MissionSessionReport, Agent, AssistantContext, AssistantMissionPermissions, Attachment, Chat, ChatCommand, ChatDetail, ChatEvent, ChatRun, RuntimeHeartbeat, Conversation, ListenOptions, ListMessages, ListMissions, ListTasks, Message, MessageContent, MessageHandler, Metadata, MissionArtifact, MissionDetail, MissionEvent, MissionEventInput, MissionSummary, MissionWorkItem, Page, Pagination, RequestOptions, RepoClaim, RepoClaimState, RepositoryCoordination, SearchAgents, SendMessage, Subscription, Task, TaskState, TotemOptions, WriteOptions, NetworkActivityPage, NetworkActionInput, NetworkActionRequest, NetworkProtectedAction } from "./types.js";
|
|
4
4
|
export * from "./types.js";
|
|
5
5
|
export * from "./errors.js";
|
|
6
6
|
export * from "./actions.js";
|
|
@@ -11,6 +11,38 @@ export declare class Totem {
|
|
|
11
11
|
static connect(options: TotemOptions): Promise<ConnectedAgent>;
|
|
12
12
|
connect(): Promise<ConnectedAgent>;
|
|
13
13
|
agent(options?: RequestOptions): Promise<Agent>;
|
|
14
|
+
activity: {
|
|
15
|
+
list: (query?: { cursor?: string; limit?: number }, options?: RequestOptions) => Promise<NetworkActivityPage>;
|
|
16
|
+
};
|
|
17
|
+
/** Native Network authorization. Human approval remains in the receiving owner's conversation. */
|
|
18
|
+
actions: {
|
|
19
|
+
list: (query?: {
|
|
20
|
+
state?: Exclude<NetworkActionRequest["state"], "expired">;
|
|
21
|
+
direction?: "inbound" | "outbound";
|
|
22
|
+
cursor?: string;
|
|
23
|
+
limit?: number;
|
|
24
|
+
}, options?: RequestOptions) => Promise<Page<NetworkActionRequest>>;
|
|
25
|
+
request: (input: NetworkActionInput, options?: WriteOptions) => Promise<NetworkActionRequest>;
|
|
26
|
+
get: (id: string, options?: RequestOptions) => Promise<NetworkActionRequest>;
|
|
27
|
+
dispatch: (id: string, input: {
|
|
28
|
+
digest: string;
|
|
29
|
+
action: NetworkProtectedAction;
|
|
30
|
+
}, options?: RequestOptions) => Promise<NetworkActionRequest>;
|
|
31
|
+
complete: (id: string, input: {
|
|
32
|
+
executionId: string;
|
|
33
|
+
outcome: "succeeded" | "failed" | "uncertain";
|
|
34
|
+
summary: string;
|
|
35
|
+
}, options?: RequestOptions) => Promise<NetworkActionRequest>;
|
|
36
|
+
cancel: (id: string, options?: RequestOptions) => Promise<NetworkActionRequest>;
|
|
37
|
+
/** Execute one registered local operation after the exact receiver approval is consumed. */
|
|
38
|
+
run: <T>(id: string, action: NetworkProtectedAction, execute: (approved: NetworkProtectedAction, executionId: string) => Promise<{
|
|
39
|
+
value: T;
|
|
40
|
+
summary: string;
|
|
41
|
+
}>, options?: RequestOptions) => Promise<{
|
|
42
|
+
value: T;
|
|
43
|
+
receipt: NetworkActionRequest;
|
|
44
|
+
}>;
|
|
45
|
+
};
|
|
14
46
|
assistant: {
|
|
15
47
|
context: (options?: RequestOptions) => Promise<AssistantContext>;
|
|
16
48
|
checks: {
|
|
@@ -195,6 +227,8 @@ export declare class Totem {
|
|
|
195
227
|
}>;
|
|
196
228
|
};
|
|
197
229
|
runtime: {
|
|
230
|
+
activations: (options?: RequestOptions) => Promise<{ data: Array<{ id: string; state: string; ready: boolean }> }>;
|
|
231
|
+
reportActivation: (input: { id: string; state: "starting" | "ready" | "blocked" | "paused"; errorCode?: "READINESS_UNSUPPORTED" | "LISTENER_START_FAILED" | "AUTHORIZATION_REJECTED" }, options?: RequestOptions) => Promise<{ recorded: boolean }>;
|
|
198
232
|
start: (input: {
|
|
199
233
|
runId: string;
|
|
200
234
|
provider: string;
|
|
@@ -233,6 +267,7 @@ export declare class Totem {
|
|
|
233
267
|
postUpdate: (id: string, text: string, options?: WriteOptions) => Promise<Message>;
|
|
234
268
|
update: (id: string, input: {
|
|
235
269
|
state: Exclude<TaskState, "submitted" | "canceled">;
|
|
270
|
+
statusMessage?: NonNullable<Task["statusMessage"]>;
|
|
236
271
|
artifacts?: Task["artifacts"];
|
|
237
272
|
expectedVersion?: number;
|
|
238
273
|
}, options?: RequestOptions) => Promise<Task>;
|