Human

Humans: ask a person, get an approval, send a notice, request a connection.

class Human

A person to reach. user.human (or new Human(), meaning the user current at each call, or the one a session or user-pinned key acts for) is the user; Human.owner() is your account's owner; new Human({ email }) is anyone else. Every method returns an operation: await req.wait() for the outcome.

via says where a message goes: "auto" (the default), or a list of "web" (only the page: you pass request.url on), "email", and for the owner "whatsapp" and "imessage", sent from NoClick's own numbers to the number they text NoClick from. "auto" is the app the owner last texted NoClick on, else email. "sms" and "call" throw NotAvailable for now. What couldn't be sent is listed in undelivered, never implied.

ownerstatic

static owner(options?: { client?: NoClick }): Human

Your account's owner: the person behind the account, reached by email and on the app they text NoClick from. Only your account reaches them: it always acts as your account, inside asUser too, and a user's session or a key pinned to a user throws PermissionDenied.

await Human.owner().notify("The site is live: https://morrowbakery.com");
Parameters
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

The owner, to message, ask, put in an agent's tools= or answer_with.

answerWith

answerWith(
  agent: Agent | string | null,
  options?: { conversation?: string },
): Promise<this>

Send what this person texts or says to NoClick's own numbers (its WhatsApp and iMessage numbers and its voice number) to agent (one of your account's). A text's reply goes back on the app they texted on once the agent's turn ends, and texts sent while it's busy go in its next turn, in order; on a call, each thing they say is a turn whose reply is read aloud as it's written. null hands them back to NoClick's assistant. Only Human.owner() reaches NoClick's numbers: your users reach an agent on a number of your own (PhoneNumber.answerWith). conversation is the agent's conversation each text or call lands in, a template over {channel} (whatsapp, imessage or call); omitted, "owner". Give an inbox and a number the same key and the person's email, calls and texts are one conversation.

const assistant = Agent.fromName("assistant");
await Human.owner().answerWith(assistant);
await assistant.message("What's on today?", { conversation: "owner" }); // the same thread
Parameters
agentAgent | string | nullrequired
options.conversationstring
Returns

This person.

answering

answering(): Promise<Agent | null>

The agent this person's texts to NoClick's own numbers go to (answerWith), or null when NoClick's assistant answers them.

Returns

The noclick.Agent, or None.

addEmail

addEmail(email: string): Promise<void>

Send a code to email for the owner of an account made by texting NoClick (which has none); confirmEmail with the code makes it theirs. Throws Conflict when the account already has an email, RateLimited after too many codes.

const owner = Human.owner();
await owner.addEmail("maya@morrowbakery.com");
await owner.confirmEmail(code);
Parameters
emailstringrequired

confirmEmail

confirmEmail(code: string): Promise<OwnerEmail>

The code addEmail sent: on a match the email is the owner's to sign in with, or, when an account already has it, that account takes this one in (merged). Whether an account has the email is said only once the code matches. status is added, or verified when an agent's turn confirmed it (it's added once that turn ends).

const confirmed = await Human.owner().confirmEmail("482913");
Parameters
codestringrequired
Returns

The confirmed email.

only

only(...tools: HumanTool[]): HumanOperations

Some of the tools this person gives an agent, for tools. In an agent's tools a Human gives it three, each addressed only to this person: notify, ask (the turn waits, awaiting_human, and the answer arrives as the next turn) and hand_off (the conversation goes to this person, with a page and an email carrying the transcript and a reply box; their replies post as person messages and the agent stays quiet until agent.handBack(conversation); on a call it's transferred to the person's phone). Policy names them human.notify, human.ask and human.hand_off.

const manager = new Human({ email: "ops@acme.com" });
await Agent.create("support", { instructions: "...", tools: ["search", manager.only("notify", "ask")] });
Parameters
toolsHumanTool[]required
Returns

A ref to just those tools of this person, to list in tools=.

ask

ask(
  message: string,
  options?: { options?: string[]; via?: Via; expiresInS?: number },
): Promise<HumanRequest<Answer>>

Ask a question; wait() resolves to an Answer.

Parameters
messagestringrequired
options.optionsstring[]
options.viaVia
options.expiresInSnumber
Returns

The request, already sent. wait() blocks until the person answers and gives what they picked (choice) and wrote (text).

approve

approve(
  message: string,
  options?: { details?: unknown; via?: Via; expiresInS?: number },
): Promise<HumanRequest<boolean>>

Ask for a yes/no; wait() resolves to true when approved.

Parameters
messagestringrequired
options.detailsunknown
options.viaVia
options.expiresInSnumber
Returns

The request, already sent. wait() gives True if they approve and False if they decline.

notify

notify(message: string, options?: { via?: Via }): Promise<HumanRequest<null>>

Send a notice (the operation succeeds once it's sent).

Parameters
messagestringrequired
options.viaVia
Returns

The request, already sent and its operation already succeeded, so wait() returns None at once. undelivered names any channel that failed.

connect

connect(
  connection: string | Connection,
  options?: { reason?: string; redirectUrl?: string },
): Promise<ConnectLink>

Ask this person to connect connection (a Connection or its name, in this person's user); wait() resolves to the connected Connection.

Parameters
connectionstring | Connectionrequired
options.reasonstring
options.redirectUrlstring
Returns

The link, already emailed: its url and when it expires_at. wait() gives the connected Connection.

HumanRequest

class HumanRequest extends Operation

A request to a person; also the operation that finishes when they answer.

Attributes
requestIdstring | null

The request's own id (the operation's is id).

requestStatusHumanRequestStatus | null

pending, answered, delivered, expired or canceled.

requestJsonObject

The request as created: url, delivered_via, undelivered, ...

urlstring | null

The page where the person answers (/h/{id}); embed or send it yourself.

deliveredViastring[]
undeliveredJsonObject[]

Channels that failed, each with a reason.

notestring | null

What the approver wrote with their answer (null until answered, or if they wrote nothing).

liststatic

static list(
  options?: HumanRequestFilters & { limit?: number },
): Promise<HumanRequest<unknown>[]>

Requests your code and agents sent, newest first (or the first limit).

Parameters
options.statusOneOrMany<HumanRequestStatus>
options.statusNotOneOrMany<HumanRequestStatus>
options.kindOneOrMany<"ask" | "approve" | "notify">
options.answerable"owner" | "code"

"owner": only requests the signed-in account owner may answer; "code": only those your code may answer with approve or decline, leaving out the ones answered only signed in to NoClick (a held purchase or deletion, whose request.signed_in_only is true).

options.limitnumber

Return at most this many.

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

Every matching request, fetched page by page. Each is also the operation you can wait() on; request_status is the request's own status.

listPagestatic

static listPage(
  options?: HumanRequestFilters & PageOptions,
): Promise<Page<HumanRequest<unknown>>>

One page of requests; pass nextCursor back as cursor.

Parameters
options.cursorstring | null

The next_cursor of the page before; omit it for the first page.

options.limitnumber

Return at most this many.

options.statusOneOrMany<HumanRequestStatus>
options.statusNotOneOrMany<HumanRequestStatus>
options.kindOneOrMany<"ask" | "approve" | "notify">
options.answerable"owner" | "code"

"owner": only requests the signed-in account owner may answer; "code": only those your code may answer with approve or decline, leaving out the ones answered only signed in to NoClick (a held purchase or deletion, whose request.signed_in_only is true).

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

(defaults to the current user)
options.clientNoClick

The client to send with; defaults to the module client built from NOCLICK_API_KEY.

Returns

A page whose data holds the requests and whose next_cursor is None on the last page.

summarystatic

static summary(options?: KindScopedFilters): Promise<OperationSummary>

How many human-request operations (ask, approve, notify) match, by operation status.

Parameters
options.clientNoClick
options.userUserOption

undefined = the ambient user (asUser), null = the account itself.

options.statusOperationStatus | "live" | readonly (OperationStatus | "live")[]

Statuses, or "live" for every non-terminal one.

options.agentstring | ApiObject

An Agent or agent id.

options.statusNotOperationStatus | readonly OperationStatus[]
options.keystring

The requesting key: its id or its prefix (nk_live_ab12).

options.createdAfterDate | string
options.createdBeforeDate | string
options.updatedAfterDate | string

Rows changed since (for polling).

options.userFilterUserFilter

Which users the read covers (user_id query), instead of acting as one (user).

Returns

The number that match in total, and per operation status in by_status.

approve

approve(options?: { note?: string }): Promise<this>

Approve it from your own code, as the person it waits on: with a key acting for your account, an approval routed to your account; with a user's session or inside asUser, one addressed to that user (anyone else gets PermissionDenied). A held operation call then runs exactly as it was held (a held shell command or other tool, the agent makes again itself), and the agent gets a turn in the same conversation with its result, its reply going out where the conversation lives: on an email thread, the same thread (the inbox agent's reply tool is bound to the thread's latest message).

Parameters
options.notestring
Returns

This request, answered: request_status is answered and note is yours.

decline

decline(options?: { note?: string }): Promise<this>

Decline it: a held call never runs, and the agent gets a turn saying so, with your note.

Parameters
options.notestring
Returns

This request, answered: request_status is answered and note is yours.

HumanOperations

class HumanOperations

Some of a person's tools for an agent (human.only(...)), for tools.

Attributes
humanHuman
toolsHumanTool[]

Answer

interface Answer

What the person chose (choice) and/or wrote (text).

Attributes
choicestring | null
textstring | null
rawunknown

The response JSON exactly as the API sent it.

OwnerEmail

interface OwnerEmail

An email confirmed for the owner (Human.confirmEmail).

Attributes
emailstring
statusstring

added, or verified when an agent's turn confirmed it: it's added once that turn ends.

mergedboolean

An account that already had the email took this one in.