@possibl/rcrt-sdk 0.1.1 → 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/CHANGELOG.md +23 -67
- package/LICENSE +21 -0
- package/README.md +2 -20
- package/dist/auth.d.ts +45 -0
- package/dist/auth.d.ts.map +1 -0
- package/{src/auth.ts → dist/auth.js} +9 -24
- package/dist/auth.js.map +1 -0
- package/dist/authn.d.ts +84 -0
- package/dist/authn.d.ts.map +1 -0
- package/dist/authn.js +75 -0
- package/dist/authn.js.map +1 -0
- package/dist/breadcrumbs.d.ts +32 -0
- package/dist/breadcrumbs.d.ts.map +1 -0
- package/dist/breadcrumbs.js +96 -0
- package/dist/breadcrumbs.js.map +1 -0
- package/dist/cards.d.ts +28 -0
- package/dist/cards.d.ts.map +1 -0
- package/dist/cards.js +106 -0
- package/dist/cards.js.map +1 -0
- package/dist/chat.d.ts +50 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +58 -0
- package/dist/chat.js.map +1 -0
- package/dist/client.d.ts +45 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +69 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +32 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +76 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/conformance.d.ts +48 -0
- package/dist/generated/conformance.d.ts.map +1 -0
- package/dist/generated/conformance.js +24 -0
- package/dist/generated/conformance.js.map +1 -0
- package/dist/generated/index.d.ts +34 -0
- package/dist/generated/index.d.ts.map +1 -0
- package/dist/generated/index.js +34 -0
- package/dist/generated/index.js.map +1 -0
- package/dist/generated/openapi.d.ts +3900 -0
- package/dist/generated/openapi.d.ts.map +1 -0
- package/dist/generated/openapi.js +6 -0
- package/dist/generated/openapi.js.map +1 -0
- package/dist/grants.d.ts +41 -0
- package/dist/grants.d.ts.map +1 -0
- package/dist/grants.js +50 -0
- package/dist/grants.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/fetch.d.ts +41 -0
- package/dist/internal/fetch.d.ts.map +1 -0
- package/dist/internal/fetch.js +106 -0
- package/dist/internal/fetch.js.map +1 -0
- package/dist/internal/sse.d.ts +82 -0
- package/dist/internal/sse.d.ts.map +1 -0
- package/dist/internal/sse.js +161 -0
- package/dist/internal/sse.js.map +1 -0
- package/dist/types/breadcrumb.d.ts +70 -0
- package/dist/types/breadcrumb.d.ts.map +1 -0
- package/dist/types/breadcrumb.js +8 -0
- package/dist/types/breadcrumb.js.map +1 -0
- package/dist/types/card.d.ts +251 -0
- package/dist/types/card.d.ts.map +1 -0
- package/dist/types/card.js +10 -0
- package/dist/types/card.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/{src/types/index.ts → dist/types/index.js} +1 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +35 -6
- package/src/authn.ts +0 -159
- package/src/breadcrumbs.ts +0 -111
- package/src/capabilities.ts +0 -93
- package/src/cards.ts +0 -109
- package/src/chat.ts +0 -83
- package/src/client.ts +0 -97
- package/src/errors.ts +0 -101
- package/src/files.ts +0 -135
- package/src/grants.ts +0 -99
- package/src/index.ts +0 -103
- package/src/internal/fetch.ts +0 -133
- package/src/internal/sse.ts +0 -236
- package/src/sessions.ts +0 -110
- package/src/types/breadcrumb.ts +0 -77
- package/src/types/card.ts +0 -298
package/src/authn.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identity module — `/v1/auth/*` endpoints.
|
|
3
|
-
*
|
|
4
|
-
* Distinct from the TokenProvider abstraction: this is the server-side
|
|
5
|
-
* identity surface that runs _after_ you've presented a bearer token.
|
|
6
|
-
* See `packages/docs/guides/02-auth.md`.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
10
|
-
import { request } from './internal/fetch.js';
|
|
11
|
-
|
|
12
|
-
export interface MeResponse {
|
|
13
|
-
user: {
|
|
14
|
-
id: string;
|
|
15
|
-
email: string;
|
|
16
|
-
name?: string;
|
|
17
|
-
picture?: string;
|
|
18
|
-
};
|
|
19
|
-
is_platform_admin: boolean;
|
|
20
|
-
organizations: Array<{ id: string; name: string; role: string }>;
|
|
21
|
-
tenants: Array<{ id: string; name: string; role: string }>;
|
|
22
|
-
active_tenant?: { id: string; name: string; role: string };
|
|
23
|
-
permissions?: string[];
|
|
24
|
-
grants?: unknown[];
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface Tenant {
|
|
28
|
-
id: string;
|
|
29
|
-
name: string;
|
|
30
|
-
org_id?: string;
|
|
31
|
-
role?: string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface PendingInvitation {
|
|
35
|
-
id: string;
|
|
36
|
-
org_id?: string | null;
|
|
37
|
-
tenant_id?: string | null;
|
|
38
|
-
email: string;
|
|
39
|
-
role: string;
|
|
40
|
-
status: 'pending' | 'accepted' | 'declined' | 'expired' | 'cancelled';
|
|
41
|
-
expires_at: string;
|
|
42
|
-
invited_by?: { id: string; name?: string };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class IdentityModule {
|
|
46
|
-
constructor(private readonly ctx: FetchContext) {}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* `GET /v1/auth/me` — returns identity + all accessible workspaces.
|
|
50
|
-
*
|
|
51
|
-
* Creates the user row on first sign-in. Call this before any other
|
|
52
|
-
* RCRT endpoint for brand-new Firebase users.
|
|
53
|
-
*/
|
|
54
|
-
async me(): Promise<MeResponse> {
|
|
55
|
-
return request<MeResponse>(this.ctx, '/v1/auth/me', { skipTenant: true });
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** List workspaces the current user is a member of. */
|
|
59
|
-
async listTenants(): Promise<Tenant[]> {
|
|
60
|
-
const res = await request<Tenant[] | { tenants: Tenant[] }>(this.ctx, '/v1/auth/tenants', {
|
|
61
|
-
skipTenant: true,
|
|
62
|
-
});
|
|
63
|
-
return Array.isArray(res) ? res : (res.tenants ?? []);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Confirm workspace membership. Client code is still responsible for setting X-Tenant-ID. */
|
|
67
|
-
async selectTenant(tenantId: string): Promise<void> {
|
|
68
|
-
await request<void>(this.ctx, `/v1/auth/tenants/${tenantId}/select`, {
|
|
69
|
-
method: 'POST',
|
|
70
|
-
skipTenant: true,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** `POST /v1/auth/logout` — server-side no-op; included for symmetry + audit. */
|
|
75
|
-
async logout(): Promise<void> {
|
|
76
|
-
await request<void>(this.ctx, '/v1/auth/logout', {
|
|
77
|
-
method: 'POST',
|
|
78
|
-
skipTenant: true,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* `POST /v1/auth/delete-account` — cascading account deletion.
|
|
84
|
-
*
|
|
85
|
-
* **NOT YET ON `development`** at publish time — pending a follow-up
|
|
86
|
-
* PR. The SDK method exists so consumer code can compile against the
|
|
87
|
-
* intended shape; invoking it against a gateway that lacks the
|
|
88
|
-
* handler returns 404.
|
|
89
|
-
*/
|
|
90
|
-
async deleteAccount(): Promise<void> {
|
|
91
|
-
await request<void>(this.ctx, '/v1/auth/delete-account', {
|
|
92
|
-
method: 'POST',
|
|
93
|
-
skipTenant: true,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** Pending invitations keyed by the caller's email. */
|
|
98
|
-
async listPendingInvitations(): Promise<PendingInvitation[]> {
|
|
99
|
-
const res = await request<
|
|
100
|
-
PendingInvitation[] | { invitations: PendingInvitation[]; total?: number }
|
|
101
|
-
>(this.ctx, '/v1/invitations/pending');
|
|
102
|
-
return Array.isArray(res) ? res : (res.invitations ?? []);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async acceptInvitation(token: string): Promise<void> {
|
|
106
|
-
await request<void>(this.ctx, '/v1/invitations/accept', {
|
|
107
|
-
method: 'POST',
|
|
108
|
-
body: { token },
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async declineInvitation(invitationId: string): Promise<void> {
|
|
113
|
-
await request<void>(this.ctx, `/v1/invitations/${invitationId}/decline`, {
|
|
114
|
-
method: 'POST',
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* `GET /v1/user/profile` — workspace-scoped user profile breadcrumb.
|
|
120
|
-
*
|
|
121
|
-
* Distinct from `me()` — this is the user's editable profile content
|
|
122
|
-
* (name, timezone, preferences) rather than their identity envelope.
|
|
123
|
-
* Returns `null` when no profile has been written yet (404 swallowed).
|
|
124
|
-
*/
|
|
125
|
-
async getUserProfile(): Promise<UserProfileBreadcrumb | null> {
|
|
126
|
-
try {
|
|
127
|
-
return await request<UserProfileBreadcrumb>(this.ctx, '/v1/user/profile');
|
|
128
|
-
} catch (err) {
|
|
129
|
-
// 404 is the no-profile-yet case — caller renders the onboarding flow.
|
|
130
|
-
if (err && typeof err === 'object' && 'status' in err && (err as { status: number }).status === 404) {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
throw err;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* `PUT /v1/user/profile` — upsert. Body fields land on the
|
|
139
|
-
* underlying breadcrumb's `content` payload.
|
|
140
|
-
*/
|
|
141
|
-
async updateUserProfile(
|
|
142
|
-
patch: Record<string, unknown>,
|
|
143
|
-
): Promise<UserProfileBreadcrumb> {
|
|
144
|
-
return request<UserProfileBreadcrumb>(this.ctx, '/v1/user/profile', {
|
|
145
|
-
method: 'PUT',
|
|
146
|
-
body: patch,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export interface UserProfileBreadcrumb {
|
|
152
|
-
id: string;
|
|
153
|
-
title?: string;
|
|
154
|
-
content: Record<string, unknown>;
|
|
155
|
-
tags: string[];
|
|
156
|
-
version: number;
|
|
157
|
-
created_at?: string;
|
|
158
|
-
updated_at?: string;
|
|
159
|
-
}
|
package/src/breadcrumbs.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Breadcrumbs module — CRUD + tag query + semantic search.
|
|
3
|
-
*
|
|
4
|
-
* See `packages/docs/guides/04-breadcrumbs.md` for the narrative
|
|
5
|
-
* description of each operation.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
9
|
-
import { request } from './internal/fetch.js';
|
|
10
|
-
import type {
|
|
11
|
-
Breadcrumb,
|
|
12
|
-
BreadcrumbResponse,
|
|
13
|
-
CreateBreadcrumbRequest,
|
|
14
|
-
UpdateBreadcrumbRequest,
|
|
15
|
-
QueryByTagsOptions,
|
|
16
|
-
SemanticSearchOptions,
|
|
17
|
-
} from './types/breadcrumb.js';
|
|
18
|
-
import { ApiError, SdkError } from './errors.js';
|
|
19
|
-
|
|
20
|
-
export class BreadcrumbsModule {
|
|
21
|
-
constructor(private readonly ctx: FetchContext) {}
|
|
22
|
-
|
|
23
|
-
/** `POST /v1/breadcrumbs` */
|
|
24
|
-
async create(req: CreateBreadcrumbRequest): Promise<Breadcrumb> {
|
|
25
|
-
const res = await request<BreadcrumbResponse | Breadcrumb>(this.ctx, '/v1/breadcrumbs', {
|
|
26
|
-
method: 'POST',
|
|
27
|
-
body: req,
|
|
28
|
-
});
|
|
29
|
-
return 'breadcrumb' in (res as BreadcrumbResponse)
|
|
30
|
-
? (res as BreadcrumbResponse).breadcrumb
|
|
31
|
-
: (res as Breadcrumb);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** `GET /v1/breadcrumbs?tags=...` — AND semantics. */
|
|
35
|
-
async queryByTags(tags: string[], options: QueryByTagsOptions = {}): Promise<Breadcrumb[]> {
|
|
36
|
-
if (tags.length === 0) {
|
|
37
|
-
throw new SdkError('EMPTY_TAGS', 'queryByTags requires at least one tag');
|
|
38
|
-
}
|
|
39
|
-
const res = await request<Breadcrumb[] | { breadcrumbs: Breadcrumb[] }>(this.ctx, '/v1/breadcrumbs', {
|
|
40
|
-
query: {
|
|
41
|
-
tags: tags.join(','),
|
|
42
|
-
limit: options.limit,
|
|
43
|
-
offset: options.offset,
|
|
44
|
-
name: options.name,
|
|
45
|
-
order: options.order,
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
return Array.isArray(res) ? res : (res.breadcrumbs ?? []);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** `GET /v1/breadcrumbs/search?q=...` — cosine-similarity semantic search. */
|
|
52
|
-
async search(q: string, options: SemanticSearchOptions = {}): Promise<Breadcrumb[]> {
|
|
53
|
-
const query: Record<string, string | number | undefined> = {
|
|
54
|
-
q,
|
|
55
|
-
limit: options.limit,
|
|
56
|
-
};
|
|
57
|
-
if (options.tags?.length) query.tags = options.tags.join(',');
|
|
58
|
-
const res = await request<Breadcrumb[] | { breadcrumbs: Breadcrumb[] }>(this.ctx, '/v1/breadcrumbs/search', { query });
|
|
59
|
-
return Array.isArray(res) ? res : (res.breadcrumbs ?? []);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** `GET /v1/breadcrumbs/{id}` */
|
|
63
|
-
async get(id: string): Promise<Breadcrumb> {
|
|
64
|
-
return request<Breadcrumb>(this.ctx, `/v1/breadcrumbs/${id}`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* `PATCH /v1/breadcrumbs/{id}` — optimistic-locking update.
|
|
69
|
-
*
|
|
70
|
-
* If `req.version` is wrong, the server returns 409. Pass
|
|
71
|
-
* `autoRetryConflict: true` to have the SDK refetch + retry once.
|
|
72
|
-
*/
|
|
73
|
-
async update(
|
|
74
|
-
id: string,
|
|
75
|
-
req: UpdateBreadcrumbRequest,
|
|
76
|
-
opts: { autoRetryConflict?: boolean } = {},
|
|
77
|
-
): Promise<Breadcrumb> {
|
|
78
|
-
const refetchBeforeRetry = opts.autoRetryConflict
|
|
79
|
-
? async () => {
|
|
80
|
-
const fresh = await this.get(id);
|
|
81
|
-
return {
|
|
82
|
-
body: {
|
|
83
|
-
...req,
|
|
84
|
-
version: fresh.version,
|
|
85
|
-
} satisfies UpdateBreadcrumbRequest,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
: undefined;
|
|
89
|
-
|
|
90
|
-
const res = await request<BreadcrumbResponse | Breadcrumb>(this.ctx, `/v1/breadcrumbs/${id}`, {
|
|
91
|
-
method: 'PATCH',
|
|
92
|
-
body: req,
|
|
93
|
-
...(refetchBeforeRetry
|
|
94
|
-
? { maxConflictRetries: 2, refetchBeforeRetry }
|
|
95
|
-
: {}),
|
|
96
|
-
});
|
|
97
|
-
return 'breadcrumb' in (res as BreadcrumbResponse)
|
|
98
|
-
? (res as BreadcrumbResponse).breadcrumb
|
|
99
|
-
: (res as Breadcrumb);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** `DELETE /v1/breadcrumbs/{id}` — soft delete. */
|
|
103
|
-
async delete(id: string): Promise<void> {
|
|
104
|
-
try {
|
|
105
|
-
await request<void>(this.ctx, `/v1/breadcrumbs/${id}`, { method: 'DELETE' });
|
|
106
|
-
} catch (err) {
|
|
107
|
-
if (err instanceof ApiError && err.status === 404) return; // idempotent
|
|
108
|
-
throw err;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
package/src/capabilities.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Capabilities module — discover what the current workspace can do.
|
|
3
|
-
*
|
|
4
|
-
* In RCRT, capabilities are breadcrumbs tagged with `interpret:*`:
|
|
5
|
-
* - `interpret:executable` — tools (functions an agent can call)
|
|
6
|
-
* - `interpret:promptable` — agents (entities the user / other
|
|
7
|
-
* agents can `chat.send()` to)
|
|
8
|
-
* - `interpret:service-def` — connectable services (Gmail, Notion,
|
|
9
|
-
* etc.) with their OAuth metadata
|
|
10
|
-
* - `interpret:knowledge` — static knowledge bases attached to the
|
|
11
|
-
* workspace
|
|
12
|
-
*
|
|
13
|
-
* This module is a thin convenience layer over `breadcrumbs.queryByTags`
|
|
14
|
-
* that maps the `type` argument to the right tag.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
18
|
-
import { request } from './internal/fetch.js';
|
|
19
|
-
import type { Breadcrumb } from './types/breadcrumb.js';
|
|
20
|
-
|
|
21
|
-
export type CapabilityType = 'tools' | 'agents' | 'services' | 'knowledge';
|
|
22
|
-
|
|
23
|
-
const TAG_BY_TYPE: Record<CapabilityType, string> = {
|
|
24
|
-
tools: 'interpret:executable',
|
|
25
|
-
agents: 'interpret:promptable',
|
|
26
|
-
services: 'interpret:service-def',
|
|
27
|
-
knowledge: 'interpret:knowledge',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export interface ChattableAgent {
|
|
31
|
-
/** The id you pass to `chat.send({ target_agent: ... })`. */
|
|
32
|
-
id: string;
|
|
33
|
-
name: string;
|
|
34
|
-
description: string;
|
|
35
|
-
/** True when this agent has the `interface:chat-default` tag. */
|
|
36
|
-
isDefault: boolean;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export class CapabilitiesModule {
|
|
40
|
-
constructor(private readonly ctx: FetchContext) {}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* List every capability of every type. Useful when surfacing the
|
|
44
|
-
* full toolbelt + agent roster to a debug / admin view.
|
|
45
|
-
*/
|
|
46
|
-
async listAll(limit: number = 200): Promise<Breadcrumb[]> {
|
|
47
|
-
const res = await request<Breadcrumb[] | { breadcrumbs: Breadcrumb[] }>(
|
|
48
|
-
this.ctx,
|
|
49
|
-
'/v1/breadcrumbs',
|
|
50
|
-
{ query: { tags: TAG_BY_TYPE.tools, limit } },
|
|
51
|
-
);
|
|
52
|
-
return Array.isArray(res) ? res : (res.breadcrumbs ?? []);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/** List capabilities of one specific type. */
|
|
56
|
-
async list(type: CapabilityType, limit: number = 200): Promise<Breadcrumb[]> {
|
|
57
|
-
const tag = TAG_BY_TYPE[type];
|
|
58
|
-
const res = await request<Breadcrumb[] | { breadcrumbs: Breadcrumb[] }>(
|
|
59
|
-
this.ctx,
|
|
60
|
-
'/v1/breadcrumbs',
|
|
61
|
-
{ query: { tags: tag, limit } },
|
|
62
|
-
);
|
|
63
|
-
return Array.isArray(res) ? res : (res.breadcrumbs ?? []);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Convenience: agents the user can chat with directly.
|
|
68
|
-
*
|
|
69
|
-
* Filters `interpret:promptable` to those tagged `interface:chat`
|
|
70
|
-
* or `interface:chat-default`. Falls back to all promptables when
|
|
71
|
-
* no agents have a chat interface tag (older deploys).
|
|
72
|
-
*/
|
|
73
|
-
async getChattableAgents(limit: number = 50): Promise<ChattableAgent[]> {
|
|
74
|
-
const promptables = await this.list('agents', limit);
|
|
75
|
-
const chatAgents = promptables.filter((bc) =>
|
|
76
|
-
bc.tags?.some(
|
|
77
|
-
(t) => t === 'interface:chat' || t === 'interface:chat-default',
|
|
78
|
-
),
|
|
79
|
-
);
|
|
80
|
-
const source = chatAgents.length > 0 ? chatAgents : promptables;
|
|
81
|
-
return source.map<ChattableAgent>((bc) => {
|
|
82
|
-
const content = (bc.content ?? {}) as Record<string, unknown>;
|
|
83
|
-
const id = (bc as { name?: string }).name ?? bc.id;
|
|
84
|
-
const name =
|
|
85
|
-
(content.name as string | undefined) ??
|
|
86
|
-
(bc as { title?: string }).title ??
|
|
87
|
-
id;
|
|
88
|
-
const description = (content.description as string | undefined) ?? '';
|
|
89
|
-
const isDefault = !!bc.tags?.includes('interface:chat-default');
|
|
90
|
-
return { id, name, description, isDefault };
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
}
|
package/src/cards.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cards module — resolve an `interpret:pending-action` breadcrumb.
|
|
3
|
-
*
|
|
4
|
-
* The card's footer action ids correspond to values the SDK writes
|
|
5
|
-
* to `content.status`. See
|
|
6
|
-
* `packages/docs/guides/06-rendering-cards.md`.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
10
|
-
import { request } from './internal/fetch.js';
|
|
11
|
-
import type { Breadcrumb } from './types/breadcrumb.js';
|
|
12
|
-
import type { Card, ResolveRequest } from './types/card.js';
|
|
13
|
-
|
|
14
|
-
export class CardsModule {
|
|
15
|
-
constructor(private readonly ctx: FetchContext) {}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* PATCH the card breadcrumb with a resolution. Handles optimistic
|
|
19
|
-
* locking transparently — refetches + retries on 409.
|
|
20
|
-
*/
|
|
21
|
-
async resolve(breadcrumbId: string, resolution: ResolveRequest): Promise<Breadcrumb> {
|
|
22
|
-
const current = await request<Breadcrumb>(this.ctx, `/v1/breadcrumbs/${breadcrumbId}`);
|
|
23
|
-
const nextContent = {
|
|
24
|
-
...(current.content ?? {}),
|
|
25
|
-
status: resolution.status,
|
|
26
|
-
user_response: resolution.user_response,
|
|
27
|
-
resolved_at: new Date().toISOString(),
|
|
28
|
-
};
|
|
29
|
-
const nextTags = ensureStatusTag(current.tags, resolution.status);
|
|
30
|
-
return request<Breadcrumb>(this.ctx, `/v1/breadcrumbs/${breadcrumbId}`, {
|
|
31
|
-
method: 'PATCH',
|
|
32
|
-
body: {
|
|
33
|
-
version: current.version,
|
|
34
|
-
content: nextContent,
|
|
35
|
-
tags: nextTags,
|
|
36
|
-
},
|
|
37
|
-
maxConflictRetries: 2,
|
|
38
|
-
refetchBeforeRetry: async () => {
|
|
39
|
-
const fresh = await request<Breadcrumb>(this.ctx, `/v1/breadcrumbs/${breadcrumbId}`);
|
|
40
|
-
return {
|
|
41
|
-
body: {
|
|
42
|
-
version: fresh.version,
|
|
43
|
-
content: {
|
|
44
|
-
...(fresh.content ?? {}),
|
|
45
|
-
status: resolution.status,
|
|
46
|
-
user_response: resolution.user_response,
|
|
47
|
-
resolved_at: new Date().toISOString(),
|
|
48
|
-
},
|
|
49
|
-
tags: ensureStatusTag(fresh.tags, resolution.status),
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Pending cards for the current user's current workspace. */
|
|
57
|
-
async listPending(limit = 50): Promise<Breadcrumb[]> {
|
|
58
|
-
const list = await request<Breadcrumb[] | { breadcrumbs: Breadcrumb[] }>(this.ctx, '/v1/breadcrumbs', {
|
|
59
|
-
query: { tags: 'interpret:pending-action,status:pending', limit },
|
|
60
|
-
});
|
|
61
|
-
return Array.isArray(list) ? list : (list.breadcrumbs ?? []);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Extract the Card object from a breadcrumb's content, normalising
|
|
66
|
-
* over legacy shapes (old breadcrumbs stored `card.type` + flat
|
|
67
|
-
* fields instead of `card.layout` + structured body).
|
|
68
|
-
*/
|
|
69
|
-
static extractCard(bc: Breadcrumb): Card | undefined {
|
|
70
|
-
const content = (bc.content ?? {}) as Record<string, unknown>;
|
|
71
|
-
const raw = (content.card as Record<string, unknown> | undefined) ?? undefined;
|
|
72
|
-
if (!raw) return undefined;
|
|
73
|
-
if (typeof raw.layout === 'string') return raw as unknown as Card;
|
|
74
|
-
// Legacy — fall back to a minimal info card.
|
|
75
|
-
if (typeof raw.type === 'string') {
|
|
76
|
-
const card: Card = {
|
|
77
|
-
layout: legacyTypeToLayout(raw.type as string),
|
|
78
|
-
header: { title: typeof content.title === 'string' ? content.title : bc.title },
|
|
79
|
-
};
|
|
80
|
-
if (typeof content.summary === 'string') {
|
|
81
|
-
card.body = { text: content.summary };
|
|
82
|
-
}
|
|
83
|
-
return card;
|
|
84
|
-
}
|
|
85
|
-
return undefined;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function ensureStatusTag(existing: string[], status: string): string[] {
|
|
90
|
-
const withoutStatus = existing.filter((t) => !t.startsWith('status:'));
|
|
91
|
-
withoutStatus.push(`status:${status}`);
|
|
92
|
-
return withoutStatus;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function legacyTypeToLayout(type: string): Card['layout'] {
|
|
96
|
-
switch (type) {
|
|
97
|
-
case 'connect':
|
|
98
|
-
return 'connect';
|
|
99
|
-
case 'confirm':
|
|
100
|
-
case 'choice':
|
|
101
|
-
case 'multi-choice':
|
|
102
|
-
case 'approval':
|
|
103
|
-
return 'decision';
|
|
104
|
-
case 'text-input':
|
|
105
|
-
return 'input';
|
|
106
|
-
default:
|
|
107
|
-
return 'info';
|
|
108
|
-
}
|
|
109
|
-
}
|
package/src/chat.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Chat module — `POST /v1/chat` + per-session / global SSE streams.
|
|
3
|
-
*
|
|
4
|
-
* See `packages/docs/guides/03-chat-and-sse.md`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
8
|
-
import { request } from './internal/fetch.js';
|
|
9
|
-
import type { SseConnection, SseConnectConfig, SseHandlers } from './internal/sse.js';
|
|
10
|
-
import { connect as sseConnect } from './internal/sse.js';
|
|
11
|
-
|
|
12
|
-
export interface SendChatRequest {
|
|
13
|
-
message: string;
|
|
14
|
-
/** The agent to route this turn to. `life-coordinator` by default in the Ritual bundle. */
|
|
15
|
-
target_agent: string;
|
|
16
|
-
/** Resume an existing session; omit to start a new one. */
|
|
17
|
-
session_id?: string;
|
|
18
|
-
/** Extra tags stamped on the user's message breadcrumb. */
|
|
19
|
-
extra_tags?: string[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface SendChatResponse {
|
|
23
|
-
id: string;
|
|
24
|
-
session_id: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface SseStreamOptions {
|
|
28
|
-
/** Override the EventSource constructor (required in React Native). */
|
|
29
|
-
eventSource?: SseConnectConfig['eventSource'];
|
|
30
|
-
useHeaderAuth?: boolean;
|
|
31
|
-
maxBackoffMs?: number;
|
|
32
|
-
/** Supply a Last-Event-ID-style resume token if your server supports it. */
|
|
33
|
-
last_event_id?: string;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class ChatModule {
|
|
37
|
-
constructor(private readonly ctx: FetchContext) {}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Send a user message to an agent. Returns immediately with the
|
|
41
|
-
* breadcrumb id + session id. The agent reply arrives via the SSE
|
|
42
|
-
* stream — call `stream(session_id)` before posting, not after.
|
|
43
|
-
*/
|
|
44
|
-
async send(req: SendChatRequest): Promise<SendChatResponse> {
|
|
45
|
-
return request<SendChatResponse>(this.ctx, '/v1/chat', {
|
|
46
|
-
method: 'POST',
|
|
47
|
-
body: req,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Per-session SSE — just this session's events. Recommended for chat views. */
|
|
52
|
-
sessionStream(sessionId: string, handlers: SseHandlers, options: SseStreamOptions = {}): SseConnection {
|
|
53
|
-
return sseConnect(this.buildConfig(`/v1/sessions/${sessionId}/stream`, options), handlers);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Global SSE — everything the user can see. Useful for home feeds / awaiting-you. */
|
|
57
|
-
globalStream(handlers: SseHandlers, options: SseStreamOptions = {}): SseConnection {
|
|
58
|
-
return sseConnect(this.buildConfig('/v1/events', options), handlers);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private buildConfig(path: string, options: SseStreamOptions): SseConnectConfig {
|
|
62
|
-
const config: SseConnectConfig = {
|
|
63
|
-
apiUrl: this.ctx.apiUrl,
|
|
64
|
-
path,
|
|
65
|
-
tenantId: this.ctx.tenantId,
|
|
66
|
-
getToken: () => this.ctx.tokenProvider.getIdToken(),
|
|
67
|
-
};
|
|
68
|
-
if (options.eventSource) config.eventSource = options.eventSource;
|
|
69
|
-
if (options.useHeaderAuth !== undefined) config.useHeaderAuth = options.useHeaderAuth;
|
|
70
|
-
if (options.maxBackoffMs !== undefined) config.maxBackoffMs = options.maxBackoffMs;
|
|
71
|
-
if (options.last_event_id) config.query = { last_event_id: options.last_event_id };
|
|
72
|
-
return config;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Clear a session's suspend flag after the loop detector fired.
|
|
77
|
-
*
|
|
78
|
-
* @see `packages/docs/operations/loop-detector.md`
|
|
79
|
-
*/
|
|
80
|
-
async resumeSession(sessionId: string): Promise<void> {
|
|
81
|
-
await request<void>(this.ctx, `/v1/sessions/${sessionId}/resume`, { method: 'POST' });
|
|
82
|
-
}
|
|
83
|
-
}
|
package/src/client.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RcrtClient — the single entry-point to the SDK.
|
|
3
|
-
*
|
|
4
|
-
* import { RcrtClient, staticTokenProvider } from '@possibl/rcrt-sdk';
|
|
5
|
-
*
|
|
6
|
-
* const rcrt = new RcrtClient({
|
|
7
|
-
* apiUrl: 'https://rcrt-api-gateway-<hash>.run.app',
|
|
8
|
-
* tokenProvider: firebaseTokenProvider(auth),
|
|
9
|
-
* });
|
|
10
|
-
*
|
|
11
|
-
* rcrt.setTenantId(workspaceId);
|
|
12
|
-
* const me = await rcrt.auth.me();
|
|
13
|
-
* const stream = rcrt.chat.sessionStream(sessionId, { ...handlers });
|
|
14
|
-
*
|
|
15
|
-
* Every module on the client shares the same fetch context — one
|
|
16
|
-
* bearer refresh path, one tenant header, one error envelope.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import type { TokenProvider } from './auth.js';
|
|
20
|
-
import type { FetchContext } from './internal/fetch.js';
|
|
21
|
-
import { BreadcrumbsModule } from './breadcrumbs.js';
|
|
22
|
-
import { ChatModule } from './chat.js';
|
|
23
|
-
import { CardsModule } from './cards.js';
|
|
24
|
-
import { GrantsModule } from './grants.js';
|
|
25
|
-
import { IdentityModule } from './authn.js';
|
|
26
|
-
import { FilesModule } from './files.js';
|
|
27
|
-
import { SessionsModule } from './sessions.js';
|
|
28
|
-
import { CapabilitiesModule } from './capabilities.js';
|
|
29
|
-
import { SdkError } from './errors.js';
|
|
30
|
-
|
|
31
|
-
export interface RcrtClientConfig {
|
|
32
|
-
apiUrl: string;
|
|
33
|
-
tokenProvider: TokenProvider;
|
|
34
|
-
/** Optional workspace UUID. Can be set later via `setTenantId()`. */
|
|
35
|
-
tenantId?: string;
|
|
36
|
-
/** Optional fetch override (SSR, custom retry, mock). */
|
|
37
|
-
fetchImpl?: typeof fetch;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export class RcrtClient {
|
|
41
|
-
private readonly ctx: FetchContext;
|
|
42
|
-
|
|
43
|
-
public readonly auth: IdentityModule;
|
|
44
|
-
public readonly breadcrumbs: BreadcrumbsModule;
|
|
45
|
-
public readonly chat: ChatModule;
|
|
46
|
-
public readonly cards: CardsModule;
|
|
47
|
-
public readonly grants: GrantsModule;
|
|
48
|
-
public readonly files: FilesModule;
|
|
49
|
-
public readonly sessions: SessionsModule;
|
|
50
|
-
public readonly capabilities: CapabilitiesModule;
|
|
51
|
-
|
|
52
|
-
constructor(config: RcrtClientConfig) {
|
|
53
|
-
if (!config.apiUrl) {
|
|
54
|
-
throw new SdkError('MISSING_API_URL', 'RcrtClient requires `apiUrl`');
|
|
55
|
-
}
|
|
56
|
-
if (!config.tokenProvider) {
|
|
57
|
-
throw new SdkError('MISSING_TOKEN_PROVIDER', 'RcrtClient requires a `tokenProvider`');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const ctxInternal = {
|
|
61
|
-
apiUrl: config.apiUrl,
|
|
62
|
-
tenantId: config.tenantId ?? null,
|
|
63
|
-
tokenProvider: config.tokenProvider,
|
|
64
|
-
fetchImpl: config.fetchImpl ?? undefined,
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// Use a Proxy so module instances can read the current `tenantId`
|
|
68
|
-
// at request time without us having to rebuild them on every
|
|
69
|
-
// `setTenantId` call.
|
|
70
|
-
this.ctx = new Proxy({} as FetchContext, {
|
|
71
|
-
get: (_target, prop) => (ctxInternal as unknown as Record<string, unknown>)[prop as string],
|
|
72
|
-
set: (_target, prop, value) => {
|
|
73
|
-
(ctxInternal as unknown as Record<string, unknown>)[prop as string] = value;
|
|
74
|
-
return true;
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
this.auth = new IdentityModule(this.ctx);
|
|
79
|
-
this.breadcrumbs = new BreadcrumbsModule(this.ctx);
|
|
80
|
-
this.chat = new ChatModule(this.ctx);
|
|
81
|
-
this.cards = new CardsModule(this.ctx);
|
|
82
|
-
this.grants = new GrantsModule(this.ctx);
|
|
83
|
-
this.files = new FilesModule(this.ctx);
|
|
84
|
-
this.sessions = new SessionsModule(this.ctx);
|
|
85
|
-
this.capabilities = new CapabilitiesModule(this.ctx);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** Switch workspaces. Subsequent requests carry the new `X-Tenant-ID`. */
|
|
89
|
-
setTenantId(tenantId: string | null): void {
|
|
90
|
-
(this.ctx as unknown as { tenantId: string | null }).tenantId = tenantId;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/** Read the workspace id this client is currently scoped to. */
|
|
94
|
-
getTenantId(): string | null {
|
|
95
|
-
return (this.ctx as unknown as { tenantId: string | null }).tenantId;
|
|
96
|
-
}
|
|
97
|
-
}
|