@jsm-mit/agent-platform-canister-package 0.0.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/README.md +133 -0
- package/declarations/agent-platform-canister/agent-platform-canister.did +120 -0
- package/declarations/agent-platform-canister/agent-platform-canister.did.d.ts +86 -0
- package/declarations/agent-platform-canister/agent-platform-canister.did.js +93 -0
- package/dist/actor-base.d.ts +48 -0
- package/dist/actor-base.d.ts.map +1 -0
- package/dist/actor-base.js +133 -0
- package/dist/actors/admin-actor.d.ts +75 -0
- package/dist/actors/admin-actor.d.ts.map +1 -0
- package/dist/actors/admin-actor.js +98 -0
- package/dist/actors/agent-configs-actor.d.ts +44 -0
- package/dist/actors/agent-configs-actor.d.ts.map +1 -0
- package/dist/actors/agent-configs-actor.js +63 -0
- package/dist/actors/chat-history-actor.d.ts +30 -0
- package/dist/actors/chat-history-actor.d.ts.map +1 -0
- package/dist/actors/chat-history-actor.js +51 -0
- package/dist/globals.d.ts +2 -0
- package/dist/globals.d.ts.map +1 -0
- package/dist/globals.js +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/interfaces.d.ts +58 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +4 -0
- package/dist/mappers.d.ts +9 -0
- package/dist/mappers.d.ts.map +1 -0
- package/dist/mappers.js +34 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Agent Platform Canister Package
|
|
2
|
+
|
|
3
|
+
A TypeScript library for interacting with the `agent-platform-canister` canister
|
|
4
|
+
on the Internet Computer — agent configs (base fields + freeform custom JSON)
|
|
5
|
+
and batched chat history for the agent platform. The wrapper is the only
|
|
6
|
+
sanctioned way to talk to the canister: it hides `HttpAgent`/`idlFactory`
|
|
7
|
+
wiring, unwraps the canister's `Framework.Result<T>` into "resolves with `T`
|
|
8
|
+
or throws a known `Error`", and converts candid `opt`/`variant`/`Principal`
|
|
9
|
+
shapes into idiomatic TypeScript.
|
|
10
|
+
|
|
11
|
+
Part of `workspace-agent-platform`; the canister itself lives in the sibling
|
|
12
|
+
`../agent-platform-canister`. Concept/architecture design lives in
|
|
13
|
+
`~/workspace-jsm-company/jsm-ideas/agent-platform/`.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @jsm-mit/agent-platform-canister-package
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### Initialization
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import {
|
|
27
|
+
AgentConfigsActor,
|
|
28
|
+
ChatHistoryActor,
|
|
29
|
+
AdminActor,
|
|
30
|
+
} from "@jsm-mit/agent-platform-canister-package";
|
|
31
|
+
|
|
32
|
+
const canisterId = "your-canister-id";
|
|
33
|
+
const agentConfigsActor = new AgentConfigsActor(canisterId, identity); // identity optional
|
|
34
|
+
const chatHistoryActor = new ChatHistoryActor(canisterId, identity);
|
|
35
|
+
const adminActor = new AdminActor(canisterId, identity);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Permissions model
|
|
39
|
+
|
|
40
|
+
Everything is admin-gated. A fresh canister has no admins — the first caller
|
|
41
|
+
of `adminActor.registerAsAdminAsyncUnsafe()` claims the role (e.g.
|
|
42
|
+
agents-village's own service identity); further admins via
|
|
43
|
+
`addAdminAsyncUnsafe`.
|
|
44
|
+
|
|
45
|
+
### Agent configs
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const config = await agentConfigsActor.upsertAgentConfigAsyncUnsafe({
|
|
49
|
+
id: "kasia",
|
|
50
|
+
name: "Kasia",
|
|
51
|
+
persona: "Jesteś Kasią, sprzedawczynią mebli...",
|
|
52
|
+
disclosesAsAi: false,
|
|
53
|
+
// tools defaults to [] when omitted (a tool-less agent); customConfigJson too is
|
|
54
|
+
// an optional escape hatch, JSON-encoded.
|
|
55
|
+
tools: [
|
|
56
|
+
{ tool: "check_availability", paramsJson: '{"serviceId":"sultana"}' },
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
// Same call again with the same id updates in place — createdAt is preserved.
|
|
60
|
+
|
|
61
|
+
const fetched = await agentConfigsActor.getAgentConfigAsyncUnsafe("kasia");
|
|
62
|
+
const all = await agentConfigsActor.listAgentConfigsAsyncUnsafe(500);
|
|
63
|
+
await agentConfigsActor.deleteAgentConfigAsyncUnsafe("kasia");
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Chat history — batched, mixed conversations/agents per call
|
|
67
|
+
|
|
68
|
+
A single flush from agents-village can mix entries from many conversations
|
|
69
|
+
and agents — that's the whole point of flushing a buffer as one call rather
|
|
70
|
+
than one call per message (AGENT-PLATFORM decision 2026-08-18). Any entry
|
|
71
|
+
naming an unknown `agentId` refuses the _whole_ batch.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
await chatHistoryActor.appendMessageBatchAsyncUnsafe([
|
|
75
|
+
{
|
|
76
|
+
conversationId: "conv-1",
|
|
77
|
+
agentId: "kasia",
|
|
78
|
+
message: { role: "user", content: "hi", timestamp: 0n },
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
conversationId: "conv-2",
|
|
82
|
+
agentId: "lilly",
|
|
83
|
+
message: { role: "user", content: "hey", timestamp: 0n },
|
|
84
|
+
},
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const history = await chatHistoryActor.getConversationHistoryAsyncUnsafe(
|
|
88
|
+
"conv-1",
|
|
89
|
+
100,
|
|
90
|
+
);
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Error model
|
|
94
|
+
|
|
95
|
+
Every `...AsyncUnsafe` method throws one of exactly three errors — switch on
|
|
96
|
+
`error.message`, details are always on `error.cause`:
|
|
97
|
+
|
|
98
|
+
- `CanisterError` — the canister returned a business `#err`;
|
|
99
|
+
`cause = { errorKey, errorMessage, logs }` (e.g. `errorKey: "NotAuthorized"`,
|
|
100
|
+
`"NotFound"`, `"InvalidData"`).
|
|
101
|
+
- `CriticalCanisterError` — transport failure or a canister trap;
|
|
102
|
+
`cause = { logs, rawError }`.
|
|
103
|
+
- `CallRefusedAtInspectionStage` — the canister's `inspect` gate refused the
|
|
104
|
+
call before execution (oversized payload or anonymous caller).
|
|
105
|
+
|
|
106
|
+
## API
|
|
107
|
+
|
|
108
|
+
- `AgentConfigsActor` — `upsertAgentConfigAsyncUnsafe`, `getAgentConfigAsyncUnsafe`,
|
|
109
|
+
`listAgentConfigsAsyncUnsafe`, `deleteAgentConfigAsyncUnsafe`.
|
|
110
|
+
- `ChatHistoryActor` — `appendMessageBatchAsyncUnsafe`, `getConversationHistoryAsyncUnsafe`.
|
|
111
|
+
- `AdminActor` — admin allowlist and diagnostics: `registerAsAdminAsyncUnsafe`,
|
|
112
|
+
`addAdminAsyncUnsafe`, `removeAdminAsyncUnsafe`, `getAdminsAsyncUnsafe`,
|
|
113
|
+
`setLoggingEnabledAsyncUnsafe`, `whoAmIAsyncUnsafe`, `getLogsAsyncUnsafe`,
|
|
114
|
+
`clearLogsAsyncUnsafe`.
|
|
115
|
+
- Configs/messages are returned as `AgentConfigView`/`ChatMessageView` (opts
|
|
116
|
+
flattened to optionals, the message role variant as a
|
|
117
|
+
`"user" | "assistant" | "tool"` string union); raw candid types remain
|
|
118
|
+
available from `.` and `./declarations/*` exports.
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
See `CLAUDE.md` for the canister-change workflow (declarations sync, wrapper
|
|
123
|
+
updates) and the integration-test policy (`npm run test-suite` runs against a
|
|
124
|
+
real mainnet test canister — human-run only).
|
|
125
|
+
|
|
126
|
+
## Requirements
|
|
127
|
+
|
|
128
|
+
- Node.js 18+
|
|
129
|
+
- TypeScript 5+
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
ISC
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
type UpsertAgentConfigArgs =
|
|
2
|
+
record {
|
|
3
|
+
customConfigJson: opt text;
|
|
4
|
+
disclosesAsAi: bool;
|
|
5
|
+
id: AgentId;
|
|
6
|
+
name: text;
|
|
7
|
+
persona: text;
|
|
8
|
+
tools: vec ToolBinding;
|
|
9
|
+
};
|
|
10
|
+
type ToolBinding =
|
|
11
|
+
record {
|
|
12
|
+
paramsJson: text;
|
|
13
|
+
tool: text;
|
|
14
|
+
};
|
|
15
|
+
type Result_6 =
|
|
16
|
+
variant {
|
|
17
|
+
err: Error;
|
|
18
|
+
ok;
|
|
19
|
+
};
|
|
20
|
+
type Result_5 =
|
|
21
|
+
variant {
|
|
22
|
+
err: Error;
|
|
23
|
+
ok: vec principal;
|
|
24
|
+
};
|
|
25
|
+
type Result_4 =
|
|
26
|
+
variant {
|
|
27
|
+
err: Error;
|
|
28
|
+
ok: vec ChatMessage;
|
|
29
|
+
};
|
|
30
|
+
type Result_3 =
|
|
31
|
+
variant {
|
|
32
|
+
err: Error;
|
|
33
|
+
ok: vec AgentConfig;
|
|
34
|
+
};
|
|
35
|
+
type Result_2 =
|
|
36
|
+
variant {
|
|
37
|
+
err: Error;
|
|
38
|
+
ok: principal;
|
|
39
|
+
};
|
|
40
|
+
type Result_1 =
|
|
41
|
+
variant {
|
|
42
|
+
err: Error;
|
|
43
|
+
ok: bool;
|
|
44
|
+
};
|
|
45
|
+
type Result =
|
|
46
|
+
variant {
|
|
47
|
+
err: Error;
|
|
48
|
+
ok: AgentConfig;
|
|
49
|
+
};
|
|
50
|
+
type MessageBatchEntry =
|
|
51
|
+
record {
|
|
52
|
+
agentId: AgentId;
|
|
53
|
+
conversationId: ConversationId;
|
|
54
|
+
message: ChatMessage;
|
|
55
|
+
};
|
|
56
|
+
type GetConversationHistoryArgs =
|
|
57
|
+
record {
|
|
58
|
+
conversationId: ConversationId;
|
|
59
|
+
limit: nat;
|
|
60
|
+
};
|
|
61
|
+
type ErrorDetails =
|
|
62
|
+
variant {
|
|
63
|
+
AlreadyExists;
|
|
64
|
+
InterCanisterConnectionError;
|
|
65
|
+
InvalidData: text;
|
|
66
|
+
NotAuthorized: text;
|
|
67
|
+
NotFound;
|
|
68
|
+
RemoteCanisterError: text;
|
|
69
|
+
ReturnsNull;
|
|
70
|
+
};
|
|
71
|
+
type Error =
|
|
72
|
+
record {
|
|
73
|
+
details: ErrorDetails;
|
|
74
|
+
logsJson: text;
|
|
75
|
+
};
|
|
76
|
+
type ConversationId = text;
|
|
77
|
+
type ChatMessageRole =
|
|
78
|
+
variant {
|
|
79
|
+
assistant;
|
|
80
|
+
tool;
|
|
81
|
+
user;
|
|
82
|
+
};
|
|
83
|
+
type ChatMessage =
|
|
84
|
+
record {
|
|
85
|
+
content: text;
|
|
86
|
+
role: ChatMessageRole;
|
|
87
|
+
timestamp: int;
|
|
88
|
+
toolCallId: opt text;
|
|
89
|
+
toolName: opt text;
|
|
90
|
+
};
|
|
91
|
+
type AppendMessageBatchArgs = record {entries: vec MessageBatchEntry;};
|
|
92
|
+
type AgentId = text;
|
|
93
|
+
type AgentConfig =
|
|
94
|
+
record {
|
|
95
|
+
createdAt: int;
|
|
96
|
+
customConfigJson: opt text;
|
|
97
|
+
disclosesAsAi: bool;
|
|
98
|
+
id: AgentId;
|
|
99
|
+
name: text;
|
|
100
|
+
persona: text;
|
|
101
|
+
tools: vec ToolBinding;
|
|
102
|
+
updatedAt: int;
|
|
103
|
+
};
|
|
104
|
+
service : {
|
|
105
|
+
addAdmin: ("principal": principal) -> (Result_1);
|
|
106
|
+
appendMessageBatch: (args: AppendMessageBatchArgs) -> (Result_6);
|
|
107
|
+
clearLogs: () -> ();
|
|
108
|
+
deleteAgentConfig: (id: AgentId) -> (Result_6);
|
|
109
|
+
getAdmins: () -> (Result_5) query;
|
|
110
|
+
getAgentConfig: (id: AgentId) -> (Result) query;
|
|
111
|
+
getConversationHistory: (args: GetConversationHistoryArgs) ->
|
|
112
|
+
(Result_4) query;
|
|
113
|
+
getLogs: () -> (text) query;
|
|
114
|
+
listAgentConfigs: (limit: nat) -> (Result_3) query;
|
|
115
|
+
registerAsAdmin: () -> (Result_2);
|
|
116
|
+
removeAdmin: ("principal": principal) -> (Result_1);
|
|
117
|
+
setLoggingEnabled: (enabled: bool) -> (Result_1);
|
|
118
|
+
upsertAgentConfig: (args: UpsertAgentConfigArgs) -> (Result);
|
|
119
|
+
whoAmI: () -> (principal) query;
|
|
120
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Principal } from "@icp-sdk/core/principal";
|
|
2
|
+
import type { ActorMethod } from "@icp-sdk/core/agent";
|
|
3
|
+
import type { IDL } from "@icp-sdk/core/candid";
|
|
4
|
+
|
|
5
|
+
export interface AgentConfig {
|
|
6
|
+
id: AgentId;
|
|
7
|
+
tools: Array<ToolBinding>;
|
|
8
|
+
name: string;
|
|
9
|
+
createdAt: bigint;
|
|
10
|
+
updatedAt: bigint;
|
|
11
|
+
persona: string;
|
|
12
|
+
disclosesAsAi: boolean;
|
|
13
|
+
customConfigJson: [] | [string];
|
|
14
|
+
}
|
|
15
|
+
export type AgentId = string;
|
|
16
|
+
export interface AppendMessageBatchArgs {
|
|
17
|
+
entries: Array<MessageBatchEntry>;
|
|
18
|
+
}
|
|
19
|
+
export interface ChatMessage {
|
|
20
|
+
content: string;
|
|
21
|
+
role: ChatMessageRole;
|
|
22
|
+
timestamp: bigint;
|
|
23
|
+
toolName: [] | [string];
|
|
24
|
+
toolCallId: [] | [string];
|
|
25
|
+
}
|
|
26
|
+
export type ChatMessageRole =
|
|
27
|
+
{ tool: null } | { user: null } | { assistant: null };
|
|
28
|
+
export type ConversationId = string;
|
|
29
|
+
export interface Error {
|
|
30
|
+
details: ErrorDetails;
|
|
31
|
+
logsJson: string;
|
|
32
|
+
}
|
|
33
|
+
export type ErrorDetails =
|
|
34
|
+
| { InterCanisterConnectionError: null }
|
|
35
|
+
| { RemoteCanisterError: string }
|
|
36
|
+
| { NotFound: null }
|
|
37
|
+
| { NotAuthorized: string }
|
|
38
|
+
| { InvalidData: string }
|
|
39
|
+
| { AlreadyExists: null }
|
|
40
|
+
| { ReturnsNull: null };
|
|
41
|
+
export interface GetConversationHistoryArgs {
|
|
42
|
+
limit: bigint;
|
|
43
|
+
conversationId: ConversationId;
|
|
44
|
+
}
|
|
45
|
+
export interface MessageBatchEntry {
|
|
46
|
+
agentId: AgentId;
|
|
47
|
+
conversationId: ConversationId;
|
|
48
|
+
message: ChatMessage;
|
|
49
|
+
}
|
|
50
|
+
export type Result = { ok: AgentConfig } | { err: Error };
|
|
51
|
+
export type Result_1 = { ok: boolean } | { err: Error };
|
|
52
|
+
export type Result_2 = { ok: Principal } | { err: Error };
|
|
53
|
+
export type Result_3 = { ok: Array<AgentConfig> } | { err: Error };
|
|
54
|
+
export type Result_4 = { ok: Array<ChatMessage> } | { err: Error };
|
|
55
|
+
export type Result_5 = { ok: Array<Principal> } | { err: Error };
|
|
56
|
+
export type Result_6 = { ok: null } | { err: Error };
|
|
57
|
+
export interface ToolBinding {
|
|
58
|
+
paramsJson: string;
|
|
59
|
+
tool: string;
|
|
60
|
+
}
|
|
61
|
+
export interface UpsertAgentConfigArgs {
|
|
62
|
+
id: AgentId;
|
|
63
|
+
tools: Array<ToolBinding>;
|
|
64
|
+
name: string;
|
|
65
|
+
persona: string;
|
|
66
|
+
disclosesAsAi: boolean;
|
|
67
|
+
customConfigJson: [] | [string];
|
|
68
|
+
}
|
|
69
|
+
export interface _SERVICE {
|
|
70
|
+
addAdmin: ActorMethod<[Principal], Result_1>;
|
|
71
|
+
appendMessageBatch: ActorMethod<[AppendMessageBatchArgs], Result_6>;
|
|
72
|
+
clearLogs: ActorMethod<[], undefined>;
|
|
73
|
+
deleteAgentConfig: ActorMethod<[AgentId], Result_6>;
|
|
74
|
+
getAdmins: ActorMethod<[], Result_5>;
|
|
75
|
+
getAgentConfig: ActorMethod<[AgentId], Result>;
|
|
76
|
+
getConversationHistory: ActorMethod<[GetConversationHistoryArgs], Result_4>;
|
|
77
|
+
getLogs: ActorMethod<[], string>;
|
|
78
|
+
listAgentConfigs: ActorMethod<[bigint], Result_3>;
|
|
79
|
+
registerAsAdmin: ActorMethod<[], Result_2>;
|
|
80
|
+
removeAdmin: ActorMethod<[Principal], Result_1>;
|
|
81
|
+
setLoggingEnabled: ActorMethod<[boolean], Result_1>;
|
|
82
|
+
upsertAgentConfig: ActorMethod<[UpsertAgentConfigArgs], Result>;
|
|
83
|
+
whoAmI: ActorMethod<[], Principal>;
|
|
84
|
+
}
|
|
85
|
+
export declare const idlFactory: IDL.InterfaceFactory;
|
|
86
|
+
export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[];
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
export const idlFactory = ({ IDL }) => {
|
|
2
|
+
const ErrorDetails = IDL.Variant({
|
|
3
|
+
InterCanisterConnectionError: IDL.Null,
|
|
4
|
+
RemoteCanisterError: IDL.Text,
|
|
5
|
+
NotFound: IDL.Null,
|
|
6
|
+
NotAuthorized: IDL.Text,
|
|
7
|
+
InvalidData: IDL.Text,
|
|
8
|
+
AlreadyExists: IDL.Null,
|
|
9
|
+
ReturnsNull: IDL.Null,
|
|
10
|
+
});
|
|
11
|
+
const Error = IDL.Record({ details: ErrorDetails, logsJson: IDL.Text });
|
|
12
|
+
const Result_1 = IDL.Variant({ ok: IDL.Bool, err: Error });
|
|
13
|
+
const AgentId = IDL.Text;
|
|
14
|
+
const ConversationId = IDL.Text;
|
|
15
|
+
const ChatMessageRole = IDL.Variant({
|
|
16
|
+
tool: IDL.Null,
|
|
17
|
+
user: IDL.Null,
|
|
18
|
+
assistant: IDL.Null,
|
|
19
|
+
});
|
|
20
|
+
const ChatMessage = IDL.Record({
|
|
21
|
+
content: IDL.Text,
|
|
22
|
+
role: ChatMessageRole,
|
|
23
|
+
timestamp: IDL.Int,
|
|
24
|
+
toolName: IDL.Opt(IDL.Text),
|
|
25
|
+
toolCallId: IDL.Opt(IDL.Text),
|
|
26
|
+
});
|
|
27
|
+
const MessageBatchEntry = IDL.Record({
|
|
28
|
+
agentId: AgentId,
|
|
29
|
+
conversationId: ConversationId,
|
|
30
|
+
message: ChatMessage,
|
|
31
|
+
});
|
|
32
|
+
const AppendMessageBatchArgs = IDL.Record({
|
|
33
|
+
entries: IDL.Vec(MessageBatchEntry),
|
|
34
|
+
});
|
|
35
|
+
const Result_6 = IDL.Variant({ ok: IDL.Null, err: Error });
|
|
36
|
+
const Result_5 = IDL.Variant({
|
|
37
|
+
ok: IDL.Vec(IDL.Principal),
|
|
38
|
+
err: Error,
|
|
39
|
+
});
|
|
40
|
+
const ToolBinding = IDL.Record({
|
|
41
|
+
paramsJson: IDL.Text,
|
|
42
|
+
tool: IDL.Text,
|
|
43
|
+
});
|
|
44
|
+
const AgentConfig = IDL.Record({
|
|
45
|
+
id: AgentId,
|
|
46
|
+
tools: IDL.Vec(ToolBinding),
|
|
47
|
+
name: IDL.Text,
|
|
48
|
+
createdAt: IDL.Int,
|
|
49
|
+
updatedAt: IDL.Int,
|
|
50
|
+
persona: IDL.Text,
|
|
51
|
+
disclosesAsAi: IDL.Bool,
|
|
52
|
+
customConfigJson: IDL.Opt(IDL.Text),
|
|
53
|
+
});
|
|
54
|
+
const Result = IDL.Variant({ ok: AgentConfig, err: Error });
|
|
55
|
+
const GetConversationHistoryArgs = IDL.Record({
|
|
56
|
+
limit: IDL.Nat,
|
|
57
|
+
conversationId: ConversationId,
|
|
58
|
+
});
|
|
59
|
+
const Result_4 = IDL.Variant({ ok: IDL.Vec(ChatMessage), err: Error });
|
|
60
|
+
const Result_3 = IDL.Variant({ ok: IDL.Vec(AgentConfig), err: Error });
|
|
61
|
+
const Result_2 = IDL.Variant({ ok: IDL.Principal, err: Error });
|
|
62
|
+
const UpsertAgentConfigArgs = IDL.Record({
|
|
63
|
+
id: AgentId,
|
|
64
|
+
tools: IDL.Vec(ToolBinding),
|
|
65
|
+
name: IDL.Text,
|
|
66
|
+
persona: IDL.Text,
|
|
67
|
+
disclosesAsAi: IDL.Bool,
|
|
68
|
+
customConfigJson: IDL.Opt(IDL.Text),
|
|
69
|
+
});
|
|
70
|
+
return IDL.Service({
|
|
71
|
+
addAdmin: IDL.Func([IDL.Principal], [Result_1], []),
|
|
72
|
+
appendMessageBatch: IDL.Func([AppendMessageBatchArgs], [Result_6], []),
|
|
73
|
+
clearLogs: IDL.Func([], [], []),
|
|
74
|
+
deleteAgentConfig: IDL.Func([AgentId], [Result_6], []),
|
|
75
|
+
getAdmins: IDL.Func([], [Result_5], ["query"]),
|
|
76
|
+
getAgentConfig: IDL.Func([AgentId], [Result], ["query"]),
|
|
77
|
+
getConversationHistory: IDL.Func(
|
|
78
|
+
[GetConversationHistoryArgs],
|
|
79
|
+
[Result_4],
|
|
80
|
+
["query"],
|
|
81
|
+
),
|
|
82
|
+
getLogs: IDL.Func([], [IDL.Text], ["query"]),
|
|
83
|
+
listAgentConfigs: IDL.Func([IDL.Nat], [Result_3], ["query"]),
|
|
84
|
+
registerAsAdmin: IDL.Func([], [Result_2], []),
|
|
85
|
+
removeAdmin: IDL.Func([IDL.Principal], [Result_1], []),
|
|
86
|
+
setLoggingEnabled: IDL.Func([IDL.Bool], [Result_1], []),
|
|
87
|
+
upsertAgentConfig: IDL.Func([UpsertAgentConfigArgs], [Result], []),
|
|
88
|
+
whoAmI: IDL.Func([], [IDL.Principal], ["query"]),
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
export const init = ({ IDL }) => {
|
|
92
|
+
return [];
|
|
93
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type ActorSubclass, HttpAgent, type Identity } from "@icp-sdk/core/agent";
|
|
2
|
+
import type { _SERVICE, Error as ErrorFromCanister } from "../declarations/agent-platform-canister/agent-platform-canister.did.js";
|
|
3
|
+
export interface LogEntry {
|
|
4
|
+
id: number;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Base class for every per-domain actor wrapper (AgentConfigsActor,
|
|
9
|
+
* ChatHistoryActor, AdminActor). Builds the HttpAgent + raw candid actor and
|
|
10
|
+
* owns the single choke point that turns the canister's Framework.Result<T>
|
|
11
|
+
* into idiomatic TS:
|
|
12
|
+
* - `{ok: T}` resolves with `T` directly.
|
|
13
|
+
* - `{err: ...}` is thrown as `Error("CanisterError", { cause: {errorKey, errorMessage, logs} })`.
|
|
14
|
+
* - An `inspect()`-stage rejection is thrown as `Error("CallRefusedAtInspectionStage")`.
|
|
15
|
+
* - Any other transport failure is thrown as `Error("CriticalCanisterError")`.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ActorBase {
|
|
18
|
+
protected canisterId: string;
|
|
19
|
+
protected identity?: Identity | undefined;
|
|
20
|
+
protected actor: ActorSubclass<_SERVICE>;
|
|
21
|
+
protected agent: HttpAgent;
|
|
22
|
+
constructor(canisterId: string, identity?: Identity | undefined);
|
|
23
|
+
private initAgentAndActor;
|
|
24
|
+
/**
|
|
25
|
+
* Rebuilds the HttpAgent and the actor from scratch. Useful for a long-lived
|
|
26
|
+
* consumer after a prolonged streak of failed calls, where a stale
|
|
27
|
+
* agent/connection is the usual suspect. Safe to call at any time.
|
|
28
|
+
*/
|
|
29
|
+
reinitializeAgent(): void;
|
|
30
|
+
protected executeFunctionAsyncUnsafe<T>(fnAsync: () => Promise<{
|
|
31
|
+
ok: T;
|
|
32
|
+
} | {
|
|
33
|
+
err: ErrorFromCanister;
|
|
34
|
+
}>): Promise<T>;
|
|
35
|
+
/**
|
|
36
|
+
* For the few diagnostic methods that do NOT return a Framework.Result (whoAmI,
|
|
37
|
+
* getLogs, clearLogs) — only the transport-level error translation applies.
|
|
38
|
+
*/
|
|
39
|
+
protected executeRawAsyncUnsafe<T>(fnAsync: () => Promise<T>): Promise<T>;
|
|
40
|
+
protected handleResultErrors(errorFromCanister: ErrorFromCanister): {
|
|
41
|
+
errorKey: string;
|
|
42
|
+
errorMessage: any;
|
|
43
|
+
logs: LogEntry[];
|
|
44
|
+
};
|
|
45
|
+
protected isInspectionRejection(error: any): boolean;
|
|
46
|
+
protected extractLogsFromError(error: any): LogEntry[] | null;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=actor-base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actor-base.d.ts","sourceRoot":"","sources":["../src/actor-base.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,KAAK,aAAa,EAClB,SAAS,EACT,KAAK,QAAQ,EAEhB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACR,QAAQ,EACR,KAAK,IAAI,iBAAiB,EAC7B,MAAM,wEAAwE,CAAC;AAGhF,MAAM,WAAW,QAAQ;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,qBAAa,SAAS;IAKd,SAAS,CAAC,UAAU,EAAE,MAAM;IAC5B,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ;IALjC,SAAS,CAAC,KAAK,EAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1C,SAAS,CAAC,KAAK,EAAG,SAAS,CAAC;gBAGd,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,QAAQ,YAAA;IAKjC,OAAO,CAAC,iBAAiB;IAWzB;;;;OAIG;IACI,iBAAiB,IAAI,IAAI;cAIhB,0BAA0B,CAAC,CAAC,EACxC,OAAO,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,CAAC,CAAA;KAAE,GAAG;QAAE,GAAG,EAAE,iBAAiB,CAAA;KAAE,CAAC,GAC/D,OAAO,CAAC,CAAC,CAAC;IAuCb;;;OAGG;cACa,qBAAqB,CAAC,CAAC,EACnC,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC;IAab,SAAS,CAAC,kBAAkB,CAAC,iBAAiB,EAAE,iBAAiB;;;;;IAqBjE,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAWpD,SAAS,CAAC,oBAAoB,CAAC,KAAK,EAAE,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI;CAyBhE"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { HttpAgent, Actor, } from "@icp-sdk/core/agent";
|
|
2
|
+
import { idlFactory } from "../declarations/agent-platform-canister/agent-platform-canister.did.js";
|
|
3
|
+
import { BetterJSON } from "@jsm-mit/utils-package";
|
|
4
|
+
/**
|
|
5
|
+
* Base class for every per-domain actor wrapper (AgentConfigsActor,
|
|
6
|
+
* ChatHistoryActor, AdminActor). Builds the HttpAgent + raw candid actor and
|
|
7
|
+
* owns the single choke point that turns the canister's Framework.Result<T>
|
|
8
|
+
* into idiomatic TS:
|
|
9
|
+
* - `{ok: T}` resolves with `T` directly.
|
|
10
|
+
* - `{err: ...}` is thrown as `Error("CanisterError", { cause: {errorKey, errorMessage, logs} })`.
|
|
11
|
+
* - An `inspect()`-stage rejection is thrown as `Error("CallRefusedAtInspectionStage")`.
|
|
12
|
+
* - Any other transport failure is thrown as `Error("CriticalCanisterError")`.
|
|
13
|
+
*/
|
|
14
|
+
export class ActorBase {
|
|
15
|
+
canisterId;
|
|
16
|
+
identity;
|
|
17
|
+
actor;
|
|
18
|
+
agent;
|
|
19
|
+
constructor(canisterId, identity) {
|
|
20
|
+
this.canisterId = canisterId;
|
|
21
|
+
this.identity = identity;
|
|
22
|
+
this.initAgentAndActor();
|
|
23
|
+
}
|
|
24
|
+
initAgentAndActor() {
|
|
25
|
+
this.agent = HttpAgent.createSync({
|
|
26
|
+
host: "https://icp0.io",
|
|
27
|
+
identity: this.identity,
|
|
28
|
+
});
|
|
29
|
+
this.actor = Actor.createActor(idlFactory, {
|
|
30
|
+
agent: this.agent,
|
|
31
|
+
canisterId: this.canisterId,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rebuilds the HttpAgent and the actor from scratch. Useful for a long-lived
|
|
36
|
+
* consumer after a prolonged streak of failed calls, where a stale
|
|
37
|
+
* agent/connection is the usual suspect. Safe to call at any time.
|
|
38
|
+
*/
|
|
39
|
+
reinitializeAgent() {
|
|
40
|
+
this.initAgentAndActor();
|
|
41
|
+
}
|
|
42
|
+
async executeFunctionAsyncUnsafe(fnAsync) {
|
|
43
|
+
let errorObj = {};
|
|
44
|
+
try {
|
|
45
|
+
const result = await fnAsync();
|
|
46
|
+
if ("ok" in result) {
|
|
47
|
+
return result.ok;
|
|
48
|
+
}
|
|
49
|
+
errorObj = this.handleResultErrors(result.err);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
// The canister's `system func inspect` rejected the call before it was ever
|
|
53
|
+
// decoded or executed (oversized payload or anonymous caller). This is a
|
|
54
|
+
// transport-level IC reject, not a decoded Framework.Result — there's never any
|
|
55
|
+
// Framework log to extract, and it's not a real "canister unreachable/crashed"
|
|
56
|
+
// scenario either, so it gets its own distinct error.
|
|
57
|
+
if (this.isInspectionRejection(err)) {
|
|
58
|
+
throw new Error("CallRefusedAtInspectionStage", { cause: err });
|
|
59
|
+
}
|
|
60
|
+
// No console output here — whatever was extractable is passed forward on `cause`
|
|
61
|
+
// instead, so callers can inspect it themselves rather than it only ever being
|
|
62
|
+
// printed and lost.
|
|
63
|
+
const logs = this.extractLogsFromError(err);
|
|
64
|
+
throw new Error("CriticalCanisterError", {
|
|
65
|
+
cause: { logs, rawError: err },
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (errorObj) {
|
|
69
|
+
throw new Error("CanisterError", { cause: errorObj });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error("UnreachableCodeError", {
|
|
73
|
+
cause: "Reached a code path that should be unreachable after error handling. Location Id: APCPA",
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* For the few diagnostic methods that do NOT return a Framework.Result (whoAmI,
|
|
79
|
+
* getLogs, clearLogs) — only the transport-level error translation applies.
|
|
80
|
+
*/
|
|
81
|
+
async executeRawAsyncUnsafe(fnAsync) {
|
|
82
|
+
try {
|
|
83
|
+
return await fnAsync();
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (this.isInspectionRejection(err)) {
|
|
87
|
+
throw new Error("CallRefusedAtInspectionStage", { cause: err });
|
|
88
|
+
}
|
|
89
|
+
throw new Error("CriticalCanisterError", {
|
|
90
|
+
cause: { logs: null, rawError: err },
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
handleResultErrors(errorFromCanister) {
|
|
95
|
+
const logs = BetterJSON.parse(errorFromCanister.logsJson, false);
|
|
96
|
+
const error = errorFromCanister.details;
|
|
97
|
+
const errorKey = Object.keys(error)[0];
|
|
98
|
+
const errorMessage = error[errorKey];
|
|
99
|
+
return {
|
|
100
|
+
errorKey: errorKey.toString(),
|
|
101
|
+
errorMessage,
|
|
102
|
+
logs,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// True if `error` is an IC transport-level reject caused by `system func inspect`
|
|
106
|
+
// returning false (`canister_inspect_message explicitly refused message`, IC0503).
|
|
107
|
+
// This text is a fixed IC/Motoko runtime message — it does not vary by which inspect
|
|
108
|
+
// check failed.
|
|
109
|
+
isInspectionRejection(error) {
|
|
110
|
+
const rejectText = error?.cause?.code?.rejectMessage || error?.message || "";
|
|
111
|
+
return rejectText.includes("canister_inspect_message explicitly refused message");
|
|
112
|
+
}
|
|
113
|
+
// On a trap, Logs.interrupt appends the request's log trail as a JSON array to the
|
|
114
|
+
// reject message — best-effort recovery of that array from the raw reject text.
|
|
115
|
+
extractLogsFromError(error) {
|
|
116
|
+
try {
|
|
117
|
+
const rejectMessage = error?.cause?.code?.rejectMessage || error?.message || "";
|
|
118
|
+
if (!rejectMessage)
|
|
119
|
+
return null;
|
|
120
|
+
const jsonStartIdx = rejectMessage.indexOf("[{");
|
|
121
|
+
const jsonEndIdx = rejectMessage.lastIndexOf("}]");
|
|
122
|
+
if (jsonStartIdx === -1 || jsonEndIdx === -1) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const rawJson = rejectMessage.substring(jsonStartIdx, jsonEndIdx + 2);
|
|
126
|
+
const logs = JSON.parse(rawJson);
|
|
127
|
+
return logs;
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type Identity } from "@icp-sdk/core/agent";
|
|
2
|
+
import { ActorBase, type LogEntry } from "../actor-base.js";
|
|
3
|
+
/** 1:1 wrapper for the canister's AdminController plus the diagnostic endpoints
|
|
4
|
+
* (whoAmI, getLogs, clearLogs). */
|
|
5
|
+
export declare class AdminActor extends ActorBase {
|
|
6
|
+
constructor(canisterId: string, identity?: Identity);
|
|
7
|
+
/**
|
|
8
|
+
* The principal the canister sees for this wrapper's identity — diagnostic endpoint,
|
|
9
|
+
* open to any caller.
|
|
10
|
+
* @returns The caller principal as text.
|
|
11
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
12
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
13
|
+
*/
|
|
14
|
+
whoAmIAsyncUnsafe(): Promise<string>;
|
|
15
|
+
/**
|
|
16
|
+
* Leftover log entries on the canister (logs are cleared per request by the canister's
|
|
17
|
+
* ok/err helpers, so this only ever shows remnants of calls that bypassed them) —
|
|
18
|
+
* diagnostic endpoint, open to any caller.
|
|
19
|
+
* @returns The parsed log entries.
|
|
20
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
21
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
22
|
+
*/
|
|
23
|
+
getLogsAsyncUnsafe(): Promise<LogEntry[]>;
|
|
24
|
+
/**
|
|
25
|
+
* Clears the canister's leftover log buffer — diagnostic endpoint, open to any caller.
|
|
26
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
27
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
28
|
+
*/
|
|
29
|
+
clearLogsAsyncUnsafe(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Adds a principal to the admin allowlist. Admin only.
|
|
32
|
+
* @param principalText - The principal (text form) to whitelist.
|
|
33
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `AlreadyExists`, anonymous principal). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
34
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
35
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
36
|
+
*/
|
|
37
|
+
addAdminAsyncUnsafe(principalText: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Removes a principal from the admin allowlist. Admin only; removing the last admin is
|
|
40
|
+
* refused.
|
|
41
|
+
* @param principalText - The principal (text form) to remove.
|
|
42
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`, last admin). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
43
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
44
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
45
|
+
*/
|
|
46
|
+
removeAdminAsyncUnsafe(principalText: string): Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* The current admin allowlist. Admin only.
|
|
49
|
+
* @returns Principals in text form.
|
|
50
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
51
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
52
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
53
|
+
*/
|
|
54
|
+
getAdminsAsyncUnsafe(): Promise<string[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Bootstrap: succeeds only while the canister has NO admin at all — the first caller
|
|
57
|
+
* claims the admin role. Once any admin exists this always refuses; further admins
|
|
58
|
+
* are added via addAdminAsyncUnsafe.
|
|
59
|
+
* @returns The registered admin principal (the caller) as text.
|
|
60
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (errorKey `NotAuthorized` once an admin is already registered). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
61
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
62
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
63
|
+
*/
|
|
64
|
+
registerAsAdminAsyncUnsafe(): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Toggles the canister's request logging (kill switch for production). Admin only.
|
|
67
|
+
* @param enabled - The new logging state.
|
|
68
|
+
* @returns The committed state.
|
|
69
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
70
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
71
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
72
|
+
*/
|
|
73
|
+
setLoggingEnabledAsyncUnsafe(enabled: boolean): Promise<boolean>;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=admin-actor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-actor.d.ts","sourceRoot":"","sources":["../../src/actors/admin-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5D;mCACmC;AACnC,qBAAa,UAAW,SAAQ,SAAS;gBACzB,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAInD;;;;;;OAMG;IACU,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC;IAOjD;;;;;;;OAOG;IACU,kBAAkB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAOtD;;;;OAIG;IACU,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlD;;;;;;OAMG;IACU,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMzE;;;;;;;OAOG;IACU,sBAAsB,CAC/B,aAAa,EAAE,MAAM,GACtB,OAAO,CAAC,OAAO,CAAC;IAMnB;;;;;;OAMG;IACU,oBAAoB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAOtD;;;;;;;;OAQG;IACU,0BAA0B,IAAI,OAAO,CAAC,MAAM,CAAC;IAO1D;;;;;;;OAOG;IACU,4BAA4B,CACrC,OAAO,EAAE,OAAO,GACjB,OAAO,CAAC,OAAO,CAAC;CAKtB"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {} from "@icp-sdk/core/agent";
|
|
2
|
+
import { Principal } from "@icp-sdk/core/principal";
|
|
3
|
+
import { BetterJSON } from "@jsm-mit/utils-package";
|
|
4
|
+
import { ActorBase } from "../actor-base.js";
|
|
5
|
+
/** 1:1 wrapper for the canister's AdminController plus the diagnostic endpoints
|
|
6
|
+
* (whoAmI, getLogs, clearLogs). */
|
|
7
|
+
export class AdminActor extends ActorBase {
|
|
8
|
+
constructor(canisterId, identity) {
|
|
9
|
+
super(canisterId, identity);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The principal the canister sees for this wrapper's identity — diagnostic endpoint,
|
|
13
|
+
* open to any caller.
|
|
14
|
+
* @returns The caller principal as text.
|
|
15
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
16
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
17
|
+
*/
|
|
18
|
+
async whoAmIAsyncUnsafe() {
|
|
19
|
+
const principal = await this.executeRawAsyncUnsafe(() => this.actor.whoAmI());
|
|
20
|
+
return principal.toText();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Leftover log entries on the canister (logs are cleared per request by the canister's
|
|
24
|
+
* ok/err helpers, so this only ever shows remnants of calls that bypassed them) —
|
|
25
|
+
* diagnostic endpoint, open to any caller.
|
|
26
|
+
* @returns The parsed log entries.
|
|
27
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
28
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
29
|
+
*/
|
|
30
|
+
async getLogsAsyncUnsafe() {
|
|
31
|
+
const logsJson = await this.executeRawAsyncUnsafe(() => this.actor.getLogs());
|
|
32
|
+
return BetterJSON.parse(logsJson, false) ?? [];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Clears the canister's leftover log buffer — diagnostic endpoint, open to any caller.
|
|
36
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister.
|
|
37
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
38
|
+
*/
|
|
39
|
+
async clearLogsAsyncUnsafe() {
|
|
40
|
+
await this.executeRawAsyncUnsafe(() => this.actor.clearLogs());
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Adds a principal to the admin allowlist. Admin only.
|
|
44
|
+
* @param principalText - The principal (text form) to whitelist.
|
|
45
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `AlreadyExists`, anonymous principal). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
46
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
47
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
48
|
+
*/
|
|
49
|
+
async addAdminAsyncUnsafe(principalText) {
|
|
50
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.addAdmin(Principal.fromText(principalText)));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Removes a principal from the admin allowlist. Admin only; removing the last admin is
|
|
54
|
+
* refused.
|
|
55
|
+
* @param principalText - The principal (text form) to remove.
|
|
56
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`, last admin). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
57
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
58
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
59
|
+
*/
|
|
60
|
+
async removeAdminAsyncUnsafe(principalText) {
|
|
61
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.removeAdmin(Principal.fromText(principalText)));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The current admin allowlist. Admin only.
|
|
65
|
+
* @returns Principals in text form.
|
|
66
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
67
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
68
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
69
|
+
*/
|
|
70
|
+
async getAdminsAsyncUnsafe() {
|
|
71
|
+
const principals = await this.executeFunctionAsyncUnsafe(() => this.actor.getAdmins());
|
|
72
|
+
return principals.map((p) => p.toText());
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Bootstrap: succeeds only while the canister has NO admin at all — the first caller
|
|
76
|
+
* claims the admin role. Once any admin exists this always refuses; further admins
|
|
77
|
+
* are added via addAdminAsyncUnsafe.
|
|
78
|
+
* @returns The registered admin principal (the caller) as text.
|
|
79
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (errorKey `NotAuthorized` once an admin is already registered). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
80
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
81
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution (anonymous caller).
|
|
82
|
+
*/
|
|
83
|
+
async registerAsAdminAsyncUnsafe() {
|
|
84
|
+
const principal = await this.executeFunctionAsyncUnsafe(() => this.actor.registerAsAdmin());
|
|
85
|
+
return principal.toText();
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Toggles the canister's request logging (kill switch for production). Admin only.
|
|
89
|
+
* @param enabled - The new logging state.
|
|
90
|
+
* @returns The committed state.
|
|
91
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
92
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
93
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
94
|
+
*/
|
|
95
|
+
async setLoggingEnabledAsyncUnsafe(enabled) {
|
|
96
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.setLoggingEnabled(enabled));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Identity } from "@icp-sdk/core/agent";
|
|
2
|
+
import { ActorBase } from "../actor-base.js";
|
|
3
|
+
import type { AgentConfigView, UpsertAgentConfigInput } from "../interfaces.js";
|
|
4
|
+
/** 1:1 wrapper for the canister's AgentConfigsController. */
|
|
5
|
+
export declare class AgentConfigsActor extends ActorBase {
|
|
6
|
+
constructor(canisterId: string, identity?: Identity);
|
|
7
|
+
/**
|
|
8
|
+
* Creates the config on first write, otherwise updates it in place —
|
|
9
|
+
* `createdAt` is preserved across an update. Admin only.
|
|
10
|
+
* @param input - The full desired config; `id` decides create-vs-update. `tools`
|
|
11
|
+
* defaults to [] (a tool-less agent) when omitted.
|
|
12
|
+
* @returns The stored config as it now stands.
|
|
13
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, or `InvalidData` — a bounded field was too long/too many entries). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
14
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
15
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
16
|
+
*/
|
|
17
|
+
upsertAgentConfigAsyncUnsafe(input: UpsertAgentConfigInput): Promise<AgentConfigView>;
|
|
18
|
+
/**
|
|
19
|
+
* Fetches one agent's config. Admin only.
|
|
20
|
+
* @param id - The agent id.
|
|
21
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
22
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
23
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
24
|
+
*/
|
|
25
|
+
getAgentConfigAsyncUnsafe(id: string): Promise<AgentConfigView>;
|
|
26
|
+
/**
|
|
27
|
+
* Lists agent configs, most-recently-created last. Admin only.
|
|
28
|
+
* @param limit - Bounded server-side to `ChatHistoryController`/`AgentConfigsController`'s
|
|
29
|
+
* `MAX_LIST_LIMIT` (500) regardless of what's passed.
|
|
30
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
31
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
32
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
33
|
+
*/
|
|
34
|
+
listAgentConfigsAsyncUnsafe(limit: number): Promise<AgentConfigView[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Deletes an agent's config. Admin only.
|
|
37
|
+
* @param id - The agent id.
|
|
38
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
39
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
40
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
41
|
+
*/
|
|
42
|
+
deleteAgentConfigAsyncUnsafe(id: string): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=agent-configs-actor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-configs-actor.d.ts","sourceRoot":"","sources":["../../src/actors/agent-configs-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAGhF,6DAA6D;AAC7D,qBAAa,iBAAkB,SAAQ,SAAS;gBAChC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAInD;;;;;;;;;OASG;IACU,4BAA4B,CACrC,KAAK,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC;IAc3B;;;;;;OAMG;IACU,yBAAyB,CAClC,EAAE,EAAE,MAAM,GACX,OAAO,CAAC,eAAe,CAAC;IAO3B;;;;;;;OAOG;IACU,2BAA2B,CACpC,KAAK,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,EAAE,CAAC;IAO7B;;;;;;OAMG;IACU,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAKvE"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {} from "@icp-sdk/core/agent";
|
|
2
|
+
import { ActorBase } from "../actor-base.js";
|
|
3
|
+
import { mapAgentConfigView, toOpt } from "../mappers.js";
|
|
4
|
+
/** 1:1 wrapper for the canister's AgentConfigsController. */
|
|
5
|
+
export class AgentConfigsActor extends ActorBase {
|
|
6
|
+
constructor(canisterId, identity) {
|
|
7
|
+
super(canisterId, identity);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates the config on first write, otherwise updates it in place —
|
|
11
|
+
* `createdAt` is preserved across an update. Admin only.
|
|
12
|
+
* @param input - The full desired config; `id` decides create-vs-update. `tools`
|
|
13
|
+
* defaults to [] (a tool-less agent) when omitted.
|
|
14
|
+
* @returns The stored config as it now stands.
|
|
15
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, or `InvalidData` — a bounded field was too long/too many entries). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
16
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
17
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
18
|
+
*/
|
|
19
|
+
async upsertAgentConfigAsyncUnsafe(input) {
|
|
20
|
+
const config = await this.executeFunctionAsyncUnsafe(() => this.actor.upsertAgentConfig({
|
|
21
|
+
id: input.id,
|
|
22
|
+
name: input.name,
|
|
23
|
+
persona: input.persona,
|
|
24
|
+
disclosesAsAi: input.disclosesAsAi,
|
|
25
|
+
tools: input.tools ?? [],
|
|
26
|
+
customConfigJson: toOpt(input.customConfigJson),
|
|
27
|
+
}));
|
|
28
|
+
return mapAgentConfigView(config);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Fetches one agent's config. Admin only.
|
|
32
|
+
* @param id - The agent id.
|
|
33
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
34
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
35
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
36
|
+
*/
|
|
37
|
+
async getAgentConfigAsyncUnsafe(id) {
|
|
38
|
+
const config = await this.executeFunctionAsyncUnsafe(() => this.actor.getAgentConfig(id));
|
|
39
|
+
return mapAgentConfigView(config);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Lists agent configs, most-recently-created last. Admin only.
|
|
43
|
+
* @param limit - Bounded server-side to `ChatHistoryController`/`AgentConfigsController`'s
|
|
44
|
+
* `MAX_LIST_LIMIT` (500) regardless of what's passed.
|
|
45
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
46
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
47
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
48
|
+
*/
|
|
49
|
+
async listAgentConfigsAsyncUnsafe(limit) {
|
|
50
|
+
const configs = await this.executeFunctionAsyncUnsafe(() => this.actor.listAgentConfigs(BigInt(limit)));
|
|
51
|
+
return configs.map(mapAgentConfigView);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Deletes an agent's config. Admin only.
|
|
55
|
+
* @param id - The agent id.
|
|
56
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound`). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
57
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
58
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
59
|
+
*/
|
|
60
|
+
async deleteAgentConfigAsyncUnsafe(id) {
|
|
61
|
+
await this.executeFunctionAsyncUnsafe(() => this.actor.deleteAgentConfig(id));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Identity } from "@icp-sdk/core/agent";
|
|
2
|
+
import { ActorBase } from "../actor-base.js";
|
|
3
|
+
import type { ChatMessageView, MessageBatchEntryInput } from "../interfaces.js";
|
|
4
|
+
/** 1:1 wrapper for the canister's ChatHistoryController. */
|
|
5
|
+
export declare class ChatHistoryActor extends ActorBase {
|
|
6
|
+
constructor(canisterId: string, identity?: Identity);
|
|
7
|
+
/**
|
|
8
|
+
* Appends a batch of message entries — a single call can mix entries from many
|
|
9
|
+
* conversations and agents (that's the point of flushing a buffer as one call,
|
|
10
|
+
* see AGENT-PLATFORM decision 2026-08-18). Admin only; any entry naming an unknown
|
|
11
|
+
* `agentId` refuses the *whole* batch, not just that entry.
|
|
12
|
+
* @param entries - Each entry pairs a message with which conversation/agent it belongs to.
|
|
13
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound` for an unknown agentId, or `InvalidData` — batch/content too large). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
14
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
15
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
16
|
+
*/
|
|
17
|
+
appendMessageBatchAsyncUnsafe(entries: MessageBatchEntryInput[]): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Fetches the most recent `limit` messages of one conversation, oldest first — a
|
|
20
|
+
* query tool for admin/debugging, not the hot path (the live conversation state
|
|
21
|
+
* lives in agents-village's own memory). Admin only.
|
|
22
|
+
* @param conversationId - Which conversation to read.
|
|
23
|
+
* @param limit - Bounded server-side to `ChatHistoryController.MAX_HISTORY_QUERY_LIMIT` (500).
|
|
24
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
25
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
26
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
27
|
+
*/
|
|
28
|
+
getConversationHistoryAsyncUnsafe(conversationId: string, limit: number): Promise<ChatMessageView[]>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=chat-history-actor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-history-actor.d.ts","sourceRoot":"","sources":["../../src/actors/chat-history-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAOhF,4DAA4D;AAC5D,qBAAa,gBAAiB,SAAQ,SAAS;gBAC/B,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ;IAInD;;;;;;;;;OASG;IACU,6BAA6B,CACtC,OAAO,EAAE,sBAAsB,EAAE,GAClC,OAAO,CAAC,IAAI,CAAC;IAkBhB;;;;;;;;;OASG;IACU,iCAAiC,CAC1C,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,GACd,OAAO,CAAC,eAAe,EAAE,CAAC;CAShC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {} from "@icp-sdk/core/agent";
|
|
2
|
+
import { ActorBase } from "../actor-base.js";
|
|
3
|
+
import { mapChatMessageView, toChatMessageRoleVariant, toOpt, } from "../mappers.js";
|
|
4
|
+
/** 1:1 wrapper for the canister's ChatHistoryController. */
|
|
5
|
+
export class ChatHistoryActor extends ActorBase {
|
|
6
|
+
constructor(canisterId, identity) {
|
|
7
|
+
super(canisterId, identity);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Appends a batch of message entries — a single call can mix entries from many
|
|
11
|
+
* conversations and agents (that's the point of flushing a buffer as one call,
|
|
12
|
+
* see AGENT-PLATFORM decision 2026-08-18). Admin only; any entry naming an unknown
|
|
13
|
+
* `agentId` refuses the *whole* batch, not just that entry.
|
|
14
|
+
* @param entries - Each entry pairs a message with which conversation/agent it belongs to.
|
|
15
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized, errorKey `NotFound` for an unknown agentId, or `InvalidData` — batch/content too large). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
16
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
17
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
18
|
+
*/
|
|
19
|
+
async appendMessageBatchAsyncUnsafe(entries) {
|
|
20
|
+
await this.executeFunctionAsyncUnsafe(() => this.actor.appendMessageBatch({
|
|
21
|
+
entries: entries.map((entry) => ({
|
|
22
|
+
conversationId: entry.conversationId,
|
|
23
|
+
agentId: entry.agentId,
|
|
24
|
+
message: {
|
|
25
|
+
role: toChatMessageRoleVariant(entry.message.role),
|
|
26
|
+
content: entry.message.content,
|
|
27
|
+
toolCallId: toOpt(entry.message.toolCallId),
|
|
28
|
+
toolName: toOpt(entry.message.toolName),
|
|
29
|
+
timestamp: entry.message.timestamp,
|
|
30
|
+
},
|
|
31
|
+
})),
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Fetches the most recent `limit` messages of one conversation, oldest first — a
|
|
36
|
+
* query tool for admin/debugging, not the hot path (the live conversation state
|
|
37
|
+
* lives in agents-village's own memory). Admin only.
|
|
38
|
+
* @param conversationId - Which conversation to read.
|
|
39
|
+
* @param limit - Bounded server-side to `ChatHistoryController.MAX_HISTORY_QUERY_LIMIT` (500).
|
|
40
|
+
* @throws Error with message `CanisterError` when the canister returns a business error (not authorized). Examine "cause" for {errorKey, errorMessage, logs}.
|
|
41
|
+
* @throws Error with message `CriticalCanisterError` when there is no communication with the canister or the canister code traps during execution.
|
|
42
|
+
* @throws Error with message `CallRefusedAtInspectionStage` when the canister's `inspect` rejects the call before execution.
|
|
43
|
+
*/
|
|
44
|
+
async getConversationHistoryAsyncUnsafe(conversationId, limit) {
|
|
45
|
+
const messages = await this.executeFunctionAsyncUnsafe(() => this.actor.getConversationHistory({
|
|
46
|
+
conversationId,
|
|
47
|
+
limit: BigInt(limit),
|
|
48
|
+
}));
|
|
49
|
+
return messages.map(mapChatMessageView);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"globals.d.ts","sourceRoot":"","sources":["../src/globals.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,oCAAoC,CAAC"}
|
package/dist/globals.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const componentName = "agent-platform-canister-package";
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ActorBase, type LogEntry } from "./actor-base.js";
|
|
2
|
+
export { AdminActor } from "./actors/admin-actor.js";
|
|
3
|
+
export { AgentConfigsActor } from "./actors/agent-configs-actor.js";
|
|
4
|
+
export { ChatHistoryActor } from "./actors/chat-history-actor.js";
|
|
5
|
+
export type { ChatMessageRoleView, ChatMessageView, MessageBatchEntryInput, AgentConfigView, UpsertAgentConfigInput, } from "./interfaces.js";
|
|
6
|
+
export { mapChatMessageRoleView, mapChatMessageView, mapAgentConfigView, } from "./mappers.js";
|
|
7
|
+
export type { ToolBinding, Error as CanisterErrorShape, ErrorDetails, } from "../declarations/agent-platform-canister/agent-platform-canister.did.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,YAAY,EACR,mBAAmB,EACnB,eAAe,EACf,sBAAsB,EACtB,eAAe,EACf,sBAAsB,GACzB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,GACrB,MAAM,cAAc,CAAC;AACtB,YAAY,EACR,WAAW,EACX,KAAK,IAAI,kBAAkB,EAC3B,YAAY,GACf,MAAM,wEAAwE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ActorBase } from "./actor-base.js";
|
|
2
|
+
export { AdminActor } from "./actors/admin-actor.js";
|
|
3
|
+
export { AgentConfigsActor } from "./actors/agent-configs-actor.js";
|
|
4
|
+
export { ChatHistoryActor } from "./actors/chat-history-actor.js";
|
|
5
|
+
export { mapChatMessageRoleView, mapChatMessageView, mapAgentConfigView, } from "./mappers.js";
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type ChatMessageRoleView = "user" | "assistant" | "tool";
|
|
2
|
+
/** Candid `ChatMessage` with the role variant as a string union and opts flattened —
|
|
3
|
+
* matches chat-agent-package's own ChatMessage shape so history round-trips without
|
|
4
|
+
* further translation on the consumer side. */
|
|
5
|
+
export interface ChatMessageView {
|
|
6
|
+
role: ChatMessageRoleView;
|
|
7
|
+
content: string;
|
|
8
|
+
toolCallId?: string;
|
|
9
|
+
toolName?: string;
|
|
10
|
+
/** Nanoseconds since epoch */
|
|
11
|
+
timestamp: bigint;
|
|
12
|
+
}
|
|
13
|
+
/** Input for ChatHistoryActor.appendMessageBatchAsyncUnsafe — role as a plain string,
|
|
14
|
+
* opts as plain optionals; the wrapper does the variant/opt shaping. */
|
|
15
|
+
export interface MessageBatchEntryInput {
|
|
16
|
+
conversationId: string;
|
|
17
|
+
agentId: string;
|
|
18
|
+
message: {
|
|
19
|
+
role: ChatMessageRoleView;
|
|
20
|
+
content: string;
|
|
21
|
+
toolCallId?: string;
|
|
22
|
+
toolName?: string;
|
|
23
|
+
timestamp: bigint;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Candid `AgentConfig` with the opt flattened. */
|
|
27
|
+
export interface AgentConfigView {
|
|
28
|
+
id: string;
|
|
29
|
+
name: string;
|
|
30
|
+
persona: string;
|
|
31
|
+
disclosesAsAi: boolean;
|
|
32
|
+
tools: {
|
|
33
|
+
tool: string;
|
|
34
|
+
paramsJson: string;
|
|
35
|
+
}[];
|
|
36
|
+
customConfigJson?: string;
|
|
37
|
+
/** Nanoseconds since epoch */
|
|
38
|
+
createdAt: bigint;
|
|
39
|
+
/** Nanoseconds since epoch */
|
|
40
|
+
updatedAt: bigint;
|
|
41
|
+
}
|
|
42
|
+
/** Input for AgentConfigsActor.upsertAgentConfigAsyncUnsafe — customConfigJson as a
|
|
43
|
+
* plain optional (candid `opt` shaping done by the wrapper); tools is optional here
|
|
44
|
+
* even though the canister's own UpsertAgentConfigArgs requires it — the wrapper
|
|
45
|
+
* defaults a missing tools to [] for a tool-less agent, so callers don't have to
|
|
46
|
+
* spell out `tools: []` every time. */
|
|
47
|
+
export interface UpsertAgentConfigInput {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
persona: string;
|
|
51
|
+
disclosesAsAi: boolean;
|
|
52
|
+
tools?: {
|
|
53
|
+
tool: string;
|
|
54
|
+
paramsJson: string;
|
|
55
|
+
}[];
|
|
56
|
+
customConfigJson?: string;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAEhE;;+CAE+C;AAC/C,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;wEACwE;AACxE,MAAM,WAAW,sBAAsB;IACnC,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACL,IAAI,EAAE,mBAAmB,CAAC;QAC1B,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;KACrB,CAAC;CACL;AAED,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;uCAIuC;AACvC,MAAM,WAAW,sBAAsB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AgentConfig, ChatMessage, ChatMessageRole } from "../declarations/agent-platform-canister/agent-platform-canister.did.js";
|
|
2
|
+
import type { ChatMessageRoleView, ChatMessageView, AgentConfigView } from "./interfaces.js";
|
|
3
|
+
declare function toOpt<T>(value: T | undefined): [] | [T];
|
|
4
|
+
export declare function mapChatMessageRoleView(role: ChatMessageRole): ChatMessageRoleView;
|
|
5
|
+
export declare function toChatMessageRoleVariant(role: ChatMessageRoleView): ChatMessageRole;
|
|
6
|
+
export declare function mapChatMessageView(message: ChatMessage): ChatMessageView;
|
|
7
|
+
export declare function mapAgentConfigView(config: AgentConfig): AgentConfigView;
|
|
8
|
+
export { toOpt };
|
|
9
|
+
//# sourceMappingURL=mappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappers.d.ts","sourceRoot":"","sources":["../src/mappers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,WAAW,EACX,WAAW,EACX,eAAe,EAClB,MAAM,wEAAwE,CAAC;AAChF,OAAO,KAAK,EACR,mBAAmB,EACnB,eAAe,EACf,eAAe,EAClB,MAAM,iBAAiB,CAAC;AAMzB,iBAAS,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAEhD;AAED,wBAAgB,sBAAsB,CAClC,IAAI,EAAE,eAAe,GACtB,mBAAmB,CAErB;AAED,wBAAgB,wBAAwB,CACpC,IAAI,EAAE,mBAAmB,GAC1B,eAAe,CAEjB;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,eAAe,CAQxE;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,eAAe,CAWvE;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
package/dist/mappers.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
function fromOpt(opt) {
|
|
2
|
+
return opt[0];
|
|
3
|
+
}
|
|
4
|
+
function toOpt(value) {
|
|
5
|
+
return value === undefined ? [] : [value];
|
|
6
|
+
}
|
|
7
|
+
export function mapChatMessageRoleView(role) {
|
|
8
|
+
return Object.keys(role)[0];
|
|
9
|
+
}
|
|
10
|
+
export function toChatMessageRoleVariant(role) {
|
|
11
|
+
return { [role]: null };
|
|
12
|
+
}
|
|
13
|
+
export function mapChatMessageView(message) {
|
|
14
|
+
return {
|
|
15
|
+
role: mapChatMessageRoleView(message.role),
|
|
16
|
+
content: message.content,
|
|
17
|
+
toolCallId: fromOpt(message.toolCallId),
|
|
18
|
+
toolName: fromOpt(message.toolName),
|
|
19
|
+
timestamp: message.timestamp,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function mapAgentConfigView(config) {
|
|
23
|
+
return {
|
|
24
|
+
id: config.id,
|
|
25
|
+
name: config.name,
|
|
26
|
+
persona: config.persona,
|
|
27
|
+
disclosesAsAi: config.disclosesAsAi,
|
|
28
|
+
tools: config.tools,
|
|
29
|
+
customConfigJson: fromOpt(config.customConfigJson),
|
|
30
|
+
createdAt: config.createdAt,
|
|
31
|
+
updatedAt: config.updatedAt,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export { toOpt };
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jsm-mit/agent-platform-canister-package",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Wrapper TypeScript package for the agent-platform-canister canister.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./declarations/*": "./declarations/*"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"declarations/"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"prepare": "npm run build",
|
|
25
|
+
"publish-public": "npm run build && npm login && npm publish --access public",
|
|
26
|
+
"typecheck": "tsc --noEmit -p tsconfig.tests.json",
|
|
27
|
+
"sync-declarations": "bash scripts/sync-declarations.sh",
|
|
28
|
+
"test-suite": "bash scripts/run-tests.sh tests/test-suite.ts",
|
|
29
|
+
"sandbox": "npx tsx sandbox/main.ts",
|
|
30
|
+
"format": "prettier --write .",
|
|
31
|
+
"format:check": "prettier --check .",
|
|
32
|
+
"guard:clean": "test -z \"$(git status --porcelain)\" || { echo '✖ Git working tree is not clean — commit your changes before publishing (published code must be a known commit).'; exit 1; }",
|
|
33
|
+
"prepublishOnly": "npm run guard:clean"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@jsm-mit/utils-package": "^0.5.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@icp-sdk/core": "^6.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@jsm-mit/cli-game-helpers": "^0.1.0",
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"dotenv": "^16.4.0",
|
|
45
|
+
"prettier": "^3.3.0",
|
|
46
|
+
"tsx": "^4.19.0",
|
|
47
|
+
"typescript": "^5.6.0",
|
|
48
|
+
"@icp-sdk/core": "^6.1.0"
|
|
49
|
+
}
|
|
50
|
+
}
|