@ambasada/village 0.8.3 → 0.8.5
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/dist/cli.mjs +297 -27
- package/dist/client.d.ts +33 -2
- package/dist/define.d.ts +1 -0
- package/dist/index.js +49 -1
- package/dist/types.d.ts +59 -3
- package/package.json +3 -3
package/dist/client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Ambasada, type AmbasadaOptions } from "@ambasada/sdk/platform";
|
|
2
2
|
import { type IncomingRequest } from "./receipt.js";
|
|
3
|
-
import type { AgentConfigInput, BuyOptions, BuyResult, ChatRequest, ChatResponse, CheckoutInput, CheckoutReceiptClaims, CheckoutSession, ImageRequest, ImageResult, LedgerPage, Listing, ListingInput, MarketOffering, PaidCall, PaymentLink, PaymentLinkInput, ToolListing, ToolResult, TranscriptEntry, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
|
|
3
|
+
import type { AgentConfigInput, BuyOptions, BuyResult, ChatRequest, ChatResponse, CheckoutInput, CheckoutReceiptClaims, CheckoutDelivery, CheckoutDeliveryInput, CheckoutSession, ImageRequest, ImageResult, LedgerPage, Listing, ListingInput, MarketOffering, PaidCall, PaymentLink, PaymentLinkInput, ToolListing, ToolResult, TranscriptEntry, ChatLine, ChatProposal, ChatTurn, TransferOptions, Wallet, WebhookDelivery, WebhookEvent } from "./types.js";
|
|
4
4
|
/** The Hack A Ton API. The platform API (`@ambasada/sdk`) is https://api.ambasada.dev. */
|
|
5
5
|
export declare const DEFAULT_VILLAGE_API_URL = "https://hackaton.ambasada.id";
|
|
6
6
|
export declare const DEFAULT_MODEL = "deepseek-v4.1-flash";
|
|
@@ -63,6 +63,20 @@ export declare class Village extends Ambasada {
|
|
|
63
63
|
idempotencyKey?: string;
|
|
64
64
|
}): Promise<CheckoutSession>;
|
|
65
65
|
getCheckout(id: string): Promise<CheckoutSession>;
|
|
66
|
+
/** Your latest Checkout sessions (newest first, default 20, at most 100), each with what you said you delivered. */
|
|
67
|
+
listCheckouts(options?: {
|
|
68
|
+
limit?: number;
|
|
69
|
+
status?: "open" | "paid" | "expired";
|
|
70
|
+
}): Promise<{
|
|
71
|
+
sessions: (CheckoutSession & {
|
|
72
|
+
delivery: Omit<CheckoutDelivery, "session"> | null;
|
|
73
|
+
})[];
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Tells the village what a paid checkout delivered (`text` ≤ 4000 chars, an https `url`, or both): the person sees it
|
|
77
|
+
* with the purchase in their app and can rate it. Again for the same session replaces it. CONFLICT before it is paid.
|
|
78
|
+
*/
|
|
79
|
+
deliverCheckout(id: string, delivery: CheckoutDeliveryInput): Promise<CheckoutDelivery>;
|
|
66
80
|
/** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
|
|
67
81
|
createPaymentLink(link: PaymentLinkInput): Promise<PaymentLink>;
|
|
68
82
|
/** Cancels an open session (`POST /v1/checkout/sessions/:id/expire`). */
|
|
@@ -136,8 +150,25 @@ export declare class Village extends Ambasada {
|
|
|
136
150
|
config: unknown;
|
|
137
151
|
limits?: unknown;
|
|
138
152
|
}>;
|
|
139
|
-
/** A message the agent answers on its next wake. */
|
|
153
|
+
/** A message from the team: the agent answers in the chat now, and reads it on its next wake. */
|
|
140
154
|
steer: (text: string) => Promise<unknown>;
|
|
155
|
+
/**
|
|
156
|
+
* Talk to your agent (docs/AGENT-CHAT.md). With `wait` (the default) it resolves with the reply, up to a
|
|
157
|
+
* minute; the same `idempotencyKey` is the same turn, so a retry never asks twice.
|
|
158
|
+
*/
|
|
159
|
+
chat: (text: string, options?: {
|
|
160
|
+
idempotencyKey?: string;
|
|
161
|
+
wait?: boolean;
|
|
162
|
+
}) => Promise<ChatTurn>;
|
|
163
|
+
/** The chat, oldest first: your words, the agent's replies and proposals, and cards for what happened. */
|
|
164
|
+
messages: (options?: {
|
|
165
|
+
since?: number;
|
|
166
|
+
limit?: number;
|
|
167
|
+
}) => Promise<ChatLine[]>;
|
|
168
|
+
/** Proposals waiting for your team. */
|
|
169
|
+
proposals: () => Promise<ChatProposal[]>;
|
|
170
|
+
/** Approve (it runs now) or decline a proposal. */
|
|
171
|
+
decide: (id: string, decision: "approve" | "decline", reason?: string) => Promise<unknown>;
|
|
141
172
|
transcript: (since?: number, limit?: number) => Promise<{
|
|
142
173
|
entries: TranscriptEntry[];
|
|
143
174
|
next_since: number;
|
package/dist/define.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export interface OfferingDef {
|
|
|
38
38
|
output?: FieldSchema;
|
|
39
39
|
/** Allow a free sample (`market.preview`). */
|
|
40
40
|
preview?: boolean;
|
|
41
|
+
/** How long the Gateway waits for your answer, ms: 100–30000 (default 30000, the most). Longer work: answer fast, finish later. */
|
|
41
42
|
timeout_ms?: number;
|
|
42
43
|
status?: "open" | "paused";
|
|
43
44
|
}
|
package/dist/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(src_exports, {
|
|
|
37
37
|
HEADERS: () => HEADERS,
|
|
38
38
|
HOSTED_MANIFEST: () => HOSTED_MANIFEST,
|
|
39
39
|
ICON_SIZE: () => ICON_SIZE,
|
|
40
|
+
MANIFEST_AGE_RATINGS: () => MANIFEST_AGE_RATINGS,
|
|
40
41
|
MANIFEST_CATEGORIES: () => MANIFEST_CATEGORIES,
|
|
41
42
|
MANIFEST_ID: () => MANIFEST_ID,
|
|
42
43
|
MANIFEST_KINDS: () => MANIFEST_KINDS,
|
|
@@ -49,6 +50,7 @@ __export(src_exports, {
|
|
|
49
50
|
MIN_PRICE_NANO: () => MIN_PRICE_NANO,
|
|
50
51
|
NANO_PER_TON: () => NANO_PER_TON,
|
|
51
52
|
NOTIFY_LIMITS: () => NOTIFY_LIMITS,
|
|
53
|
+
OFFERING_TIMEOUT_MS: () => OFFERING_TIMEOUT_MS,
|
|
52
54
|
RECEIPT_HEADER: () => RECEIPT_HEADER,
|
|
53
55
|
ReceiptError: () => ReceiptError,
|
|
54
56
|
SHELL_TOKEN_TTL_S: () => SHELL_TOKEN_TTL_S,
|
|
@@ -82,6 +84,7 @@ __export(src_exports, {
|
|
|
82
84
|
leafHash: () => leafHash,
|
|
83
85
|
listingLine: () => listingLine,
|
|
84
86
|
nodeHash: () => nodeHash,
|
|
87
|
+
offeringTimeoutProblem: () => offeringTimeoutProblem,
|
|
85
88
|
parseCheckpoint: () => parseCheckpoint,
|
|
86
89
|
parseVerifierKey: () => parseVerifierKey,
|
|
87
90
|
pngInfo: () => pngInfo,
|
|
@@ -152,6 +155,8 @@ var ERROR_STATUS = {
|
|
|
152
155
|
BUDGET_EXCEEDED: 402,
|
|
153
156
|
CAP_INBOX_RATE: 429,
|
|
154
157
|
// inbox texts: 20 an hour, 1 unsolicited per counterparty an hour (EXCHANGE.md §8)
|
|
158
|
+
CAP_CHAT_RATE: 429,
|
|
159
|
+
// turns of the CEO chat per company (docs/AGENT-CHAT.md)
|
|
155
160
|
// Additions needed by the gateway and bank
|
|
156
161
|
UPSTREAM_ERROR: 502,
|
|
157
162
|
PRICE_ABOVE_MAX: 409,
|
|
@@ -1141,6 +1146,7 @@ var MANIFEST_SCHEMA = 2;
|
|
|
1141
1146
|
var MANIFEST_KINDS = ["product", "event", "tool", "assistant"];
|
|
1142
1147
|
var MANIFEST_CATEGORIES = ["shopping", "food", "events", "tools", "learning", "community", "games", "finance", "other"];
|
|
1143
1148
|
var MANIFEST_VISIBILITY = ["public", "builders", "unlisted"];
|
|
1149
|
+
var MANIFEST_AGE_RATINGS = ["4+", "9+", "12+", "17+"];
|
|
1144
1150
|
var MANIFEST_LIMITS = { id: 32, name: 32, subtitle: 40, description: 170, tags: 5, screenshots: 3 };
|
|
1145
1151
|
var MANIFEST_ID = /^[a-z0-9-]{3,32}$/;
|
|
1146
1152
|
var HOSTED_MANIFEST = /^https:\/\/hub\.ambasada\.id\/api\/apps\/([a-z0-9-]+)\/manifest$/;
|
|
@@ -1201,6 +1207,15 @@ function validateManifest(json) {
|
|
|
1201
1207
|
const color = splash?.color;
|
|
1202
1208
|
if (!splash || color !== void 0 && (typeof color !== "string" || !HEX_COLOR.test(color))) problem("splash_color", `"splash.color" must be a #RRGGBB colour (got ${JSON.stringify(color ?? m.splash)})`);
|
|
1203
1209
|
}
|
|
1210
|
+
const age = str("age_rating");
|
|
1211
|
+
if (m.age_rating === void 0) {
|
|
1212
|
+
if (m.schema === MANIFEST_SCHEMA) problem("age_rating", `"age_rating" is required: one of ${MANIFEST_AGE_RATINGS.join(", ")} (the hub refuses to register an app without it)`);
|
|
1213
|
+
} else if (!age || !MANIFEST_AGE_RATINGS.includes(age)) {
|
|
1214
|
+
problem("age_rating", `"age_rating" must be one of ${MANIFEST_AGE_RATINGS.join(", ")} (got ${JSON.stringify(m.age_rating)})`);
|
|
1215
|
+
}
|
|
1216
|
+
if (m.support !== void 0 && (typeof m.support !== "string" || !/^(mailto:[^@\s]+@[^@\s]+|https:\/\/\S+)$/.test(m.support))) {
|
|
1217
|
+
problem("support", `"support" must be a mailto: address or an https URL (got ${JSON.stringify(m.support)})`);
|
|
1218
|
+
}
|
|
1204
1219
|
const kind = str("kind");
|
|
1205
1220
|
if (m.kind !== void 0 && (!kind || !MANIFEST_KINDS.includes(kind))) warn("kind", `unknown "kind" ${JSON.stringify(m.kind)}: the app knows ${MANIFEST_KINDS.join(", ")} and shows this one as a product`);
|
|
1206
1221
|
const category = str("category");
|
|
@@ -1462,6 +1477,12 @@ var HEADERS = {
|
|
|
1462
1477
|
idempotentReplay: "idempotent-replayed"
|
|
1463
1478
|
};
|
|
1464
1479
|
var MAX_DEPTH = 4;
|
|
1480
|
+
var OFFERING_TIMEOUT_MS = { min: 100, max: 3e4 };
|
|
1481
|
+
function offeringTimeoutProblem(value) {
|
|
1482
|
+
if (value === void 0) return null;
|
|
1483
|
+
const n = Number(value);
|
|
1484
|
+
return Number.isInteger(n) && n >= OFFERING_TIMEOUT_MS.min && n <= OFFERING_TIMEOUT_MS.max ? null : `timeout_ms must be between ${OFFERING_TIMEOUT_MS.min} and ${OFFERING_TIMEOUT_MS.max} (got ${JSON.stringify(value)})`;
|
|
1485
|
+
}
|
|
1465
1486
|
|
|
1466
1487
|
// src/receipt.ts
|
|
1467
1488
|
import { AmbasadaError as AmbasadaError2, getHeader } from "@ambasada/sdk/platform";
|
|
@@ -1698,6 +1719,20 @@ var Village = class extends Ambasada {
|
|
|
1698
1719
|
getCheckout(id) {
|
|
1699
1720
|
return this.call("GET", `/v1/checkout/sessions/${encodeURIComponent(id)}`);
|
|
1700
1721
|
}
|
|
1722
|
+
/** Your latest Checkout sessions (newest first, default 20, at most 100), each with what you said you delivered. */
|
|
1723
|
+
listCheckouts(options = {}) {
|
|
1724
|
+
const q = new URLSearchParams();
|
|
1725
|
+
if (options.limit !== void 0) q.set("limit", String(options.limit));
|
|
1726
|
+
if (options.status) q.set("status", options.status);
|
|
1727
|
+
return this.call("GET", `/v1/checkout/sessions${q.size ? `?${q}` : ""}`);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Tells the village what a paid checkout delivered (`text` ≤ 4000 chars, an https `url`, or both): the person sees it
|
|
1731
|
+
* with the purchase in their app and can rate it. Again for the same session replaces it. CONFLICT before it is paid.
|
|
1732
|
+
*/
|
|
1733
|
+
deliverCheckout(id, delivery) {
|
|
1734
|
+
return this.call("POST", `/v1/checkout/sessions/${encodeURIComponent(id)}/delivery`, { body: delivery });
|
|
1735
|
+
}
|
|
1701
1736
|
/** A reusable payment link for static pages (`<button data-village-pay="pl_…">` with pay.js). */
|
|
1702
1737
|
createPaymentLink(link) {
|
|
1703
1738
|
return this.call("POST", "/v1/checkout/links", { body: link });
|
|
@@ -1841,8 +1876,19 @@ var Village = class extends Ambasada {
|
|
|
1841
1876
|
agent = {
|
|
1842
1877
|
/** Replaces the agent's prompt (`agent.md`) and settings (`settings.json`). */
|
|
1843
1878
|
config: (config) => this.call("POST", "/v1/agent/config", { body: config }),
|
|
1844
|
-
/** A message the agent answers on its next wake. */
|
|
1879
|
+
/** A message from the team: the agent answers in the chat now, and reads it on its next wake. */
|
|
1845
1880
|
steer: (text) => this.call("POST", "/v1/agent/steer", { body: { text } }),
|
|
1881
|
+
/**
|
|
1882
|
+
* Talk to your agent (docs/AGENT-CHAT.md). With `wait` (the default) it resolves with the reply, up to a
|
|
1883
|
+
* minute; the same `idempotencyKey` is the same turn, so a retry never asks twice.
|
|
1884
|
+
*/
|
|
1885
|
+
chat: (text, options = {}) => this.call("POST", "/v1/agent/chat/turn", { body: { text, wait: options.wait ?? true, idempotency_key: options.idempotencyKey ?? randomKey() } }),
|
|
1886
|
+
/** The chat, oldest first: your words, the agent's replies and proposals, and cards for what happened. */
|
|
1887
|
+
messages: async (options = {}) => (await this.call("GET", "/v1/agent/chat/messages", { query: { limit: options.limit ?? 50, ...options.since ? { since: options.since } : {} } })).messages,
|
|
1888
|
+
/** Proposals waiting for your team. */
|
|
1889
|
+
proposals: async () => (await this.call("GET", "/v1/agent/chat/proposals")).proposals,
|
|
1890
|
+
/** Approve (it runs now) or decline a proposal. */
|
|
1891
|
+
decide: (id, decision, reason) => this.call("POST", `/v1/agent/chat/proposals/${encodeURIComponent(id)}`, { body: { decision, ...reason ? { reason } : {} } }),
|
|
1846
1892
|
transcript: (since = 0, limit = 200) => this.call("GET", "/v1/agent/transcript", { query: { since, limit } }),
|
|
1847
1893
|
state: () => this.call("GET", "/v1/agent/state")
|
|
1848
1894
|
};
|
|
@@ -1860,6 +1906,8 @@ function defineCompany(app, village2) {
|
|
|
1860
1906
|
function offering(def) {
|
|
1861
1907
|
if (!/^[a-z0-9][a-z0-9_-]{0,63}$/.test(def.name)) throw new Error(`offering name "${def.name}" must be a slug (a-z, 0-9, _, -)`);
|
|
1862
1908
|
if (!(def.price >= 0.1 && def.price <= 500)) throw new Error(`offering ${def.name}: price must be between 0.1 and 500 TON`);
|
|
1909
|
+
const timeout = offeringTimeoutProblem(def.timeout_ms);
|
|
1910
|
+
if (timeout) throw new Error(`offering ${def.name}: ${timeout}`);
|
|
1863
1911
|
return def;
|
|
1864
1912
|
}
|
|
1865
1913
|
|
package/dist/types.d.ts
CHANGED
|
@@ -55,6 +55,17 @@ export interface CheckoutInput {
|
|
|
55
55
|
/** Seconds, 300–86400 (default 3600). */
|
|
56
56
|
expires_in?: number;
|
|
57
57
|
}
|
|
58
|
+
/** What a paid checkout delivered (`POST /v1/checkout/sessions/:id/delivery`): text, an https URL, or both. */
|
|
59
|
+
export interface CheckoutDeliveryInput {
|
|
60
|
+
text?: string;
|
|
61
|
+
url?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface CheckoutDelivery {
|
|
64
|
+
session: string;
|
|
65
|
+
text: string | null;
|
|
66
|
+
url: string | null;
|
|
67
|
+
at: string;
|
|
68
|
+
}
|
|
58
69
|
export interface CheckoutSession {
|
|
59
70
|
id: string;
|
|
60
71
|
object: "checkout.session";
|
|
@@ -142,7 +153,8 @@ export interface BuyResult<Output = any> {
|
|
|
142
153
|
/** For `need()`: which offering served it (`company/name`), if the Gateway says. */
|
|
143
154
|
offering: string | null;
|
|
144
155
|
}
|
|
145
|
-
|
|
156
|
+
/** What the village sells (apps/api/config/pricing.json); any other model is refused. */
|
|
157
|
+
export type ChatModel = "deepseek-v4.1-flash" | (string & {});
|
|
146
158
|
export interface ChatMessage {
|
|
147
159
|
role: "system" | "user" | "assistant" | "tool";
|
|
148
160
|
content: string;
|
|
@@ -258,7 +270,7 @@ export interface TransferOptions {
|
|
|
258
270
|
}
|
|
259
271
|
/** `agent/settings.json`, sent with the prompt to `POST /v1/agent/config` (agent stream wire format). */
|
|
260
272
|
export interface AgentSettings {
|
|
261
|
-
model?: "deepseek-v4.1-flash"
|
|
273
|
+
model?: "deepseek-v4.1-flash";
|
|
262
274
|
enabled?: boolean;
|
|
263
275
|
wake?: {
|
|
264
276
|
interval_minutes?: number;
|
|
@@ -272,7 +284,12 @@ export interface AgentSettings {
|
|
|
272
284
|
};
|
|
273
285
|
/** Agent tools offered to the model (default: all). */
|
|
274
286
|
tools?: string[];
|
|
275
|
-
/**
|
|
287
|
+
/**
|
|
288
|
+
* The whole company's spend limits, TON: the product's own LLM and image calls count too, not only the agent's
|
|
289
|
+
* purchases. Over `auto_per_payment` (and `auto_per_day`) an agent payment needs the team's approval.
|
|
290
|
+
*/
|
|
291
|
+
company_limits?: AgentSettings["limits"];
|
|
292
|
+
/** @deprecated The 0.8 name of `company_limits` (they were always the company's, not only the agent's). */
|
|
276
293
|
limits?: {
|
|
277
294
|
per_payment?: number;
|
|
278
295
|
per_hour?: number;
|
|
@@ -296,6 +313,45 @@ export interface TranscriptEntry {
|
|
|
296
313
|
data?: unknown;
|
|
297
314
|
[key: string]: unknown;
|
|
298
315
|
}
|
|
316
|
+
/** Something the agent wants to do, waiting for the team in the chat (docs/AGENT-CHAT.md). */
|
|
317
|
+
export interface ChatProposal {
|
|
318
|
+
/** What `agent.decide(id, …)` takes. */
|
|
319
|
+
id: string;
|
|
320
|
+
tool: string;
|
|
321
|
+
/** One plain sentence: "Change the price of translate to 1.2 TON". */
|
|
322
|
+
text: string;
|
|
323
|
+
input: unknown;
|
|
324
|
+
risk?: "low" | "medium" | "high";
|
|
325
|
+
state: "pending" | "approved" | "declined" | "done" | "failed";
|
|
326
|
+
}
|
|
327
|
+
/** One line of the chat with your agent: your words, its reply (with proposals), or a card for what happened. */
|
|
328
|
+
export interface ChatLine {
|
|
329
|
+
id: string;
|
|
330
|
+
role: "user" | "agent" | "card" | "village";
|
|
331
|
+
at: number | null;
|
|
332
|
+
text: string;
|
|
333
|
+
card?: {
|
|
334
|
+
id: string;
|
|
335
|
+
kind: string;
|
|
336
|
+
title: string;
|
|
337
|
+
body?: string | null;
|
|
338
|
+
delta_ton?: number | null;
|
|
339
|
+
from?: string | null;
|
|
340
|
+
at: number;
|
|
341
|
+
};
|
|
342
|
+
proposals?: ChatProposal[];
|
|
343
|
+
cost_ton?: number;
|
|
344
|
+
}
|
|
345
|
+
export interface ChatTurn {
|
|
346
|
+
submission_id: string;
|
|
347
|
+
message_id: string;
|
|
348
|
+
/** false when this idempotency key was already sent: the same turn, not a new one. */
|
|
349
|
+
accepted: boolean;
|
|
350
|
+
/** With `wait`: how the turn ended and the agent's reply. */
|
|
351
|
+
status?: "completed" | "error" | "aborted" | "skipped" | "pending" | "running";
|
|
352
|
+
error?: string;
|
|
353
|
+
reply?: ChatLine | null;
|
|
354
|
+
}
|
|
299
355
|
export interface MarketOffering {
|
|
300
356
|
id: string;
|
|
301
357
|
company?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ambasada/village",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.5",
|
|
4
4
|
"description": "The Hack A Ton add-on for Ambasada apps: TON checkout, receipts, offerings, LLM, the agent, the market; CLI commands and the local bank.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"node": ">=22"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@ambasada/sdk": "^0.8.
|
|
30
|
+
"@ambasada/sdk": "^0.8.5"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/node": "^22.20.5",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"typescript": "~5.9.3",
|
|
36
36
|
"vitest": "^4.1.12",
|
|
37
37
|
"@ambasada/protocol": "0.1.0",
|
|
38
|
-
"@ambasada/cli": "0.8.
|
|
38
|
+
"@ambasada/cli": "0.8.5"
|
|
39
39
|
},
|
|
40
40
|
"author": "CENTYSO (https://centyso.com)",
|
|
41
41
|
"homepage": "https://ambasada.id",
|